package org.jsola.hr.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.jsola.common.*;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.common.HrKit;
import org.jsola.hr.constant.DateType;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.constant.PunchStatus;
import org.jsola.hr.constant.PunchType;
import org.jsola.hr.dao.IAttendPunchRecordDAO;
import org.jsola.hr.dto.AttendPunchRecordAddDTO;
import org.jsola.hr.dto.AttendPunchRecordUpdateDTO;
import org.jsola.hr.dto.CompanyAdditionalFieldsAddDTO;
import org.jsola.hr.dto.PunchCommonDTO;
import org.jsola.hr.dto.attendschedule.AttendPeriodDTO;
import org.jsola.hr.dto.excel.AttendPunchRecordImportDTO;
import org.jsola.hr.entity.*;
import org.jsola.hr.exception.HrException;
import org.jsola.hr.provider.IGregorianCalendarProviderService;
import org.jsola.hr.provider.IUserProviderService;
import org.jsola.hr.query.*;
import org.jsola.hr.service.*;
import org.jsola.hr.service.excel.AttendPunchNoModelDataListener;
import org.jsola.hr.service.excel.AttendPunchRecordImportListener;
import org.jsola.hr.vo.*;
import org.jsola.hr.vo.excel.AttendPunchRecordExportVO;
import org.jsola.hr.vo.excel.AttendanceSheetResultVO;
import org.jsola.hr.vo.excel.ParseResultVO;
import org.jsola.user.core.TokenUser;
import org.jsola.user.entity.UserDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;

import java.io.File;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 考勤打卡记录
 *
 * @author zhr
 */
@Service("hrAttendPunchRecordServiceImpl")
@Slf4j
public class AttendPunchRecordServiceImpl implements IAttendPunchRecordService {

    @Autowired
    private IAttendPunchRecordDAO attendPunchRecordDAO;
    @Autowired
    private IAttendPlanService attendPlanService;
    @Autowired
    private IAttendPunchTimeService attendPunchTimeService;
    @Autowired
    private IAttendCalendarService attendCalendarService;
    @Autowired
    private IGregorianCalendarProviderService gregorianCalendarProviderService;
    @Autowired
    private IAttendPunchCommonService attendPunchCommonService;
    @Autowired
    private IEmpInfoService empInfoService;
    @Autowired
    private IAttendPunchCalibrationService attendPunchCalibrationService;
    @Autowired
    private IUserProviderService userProviderService;
    @Autowired
    private IAttendExtraJsonService attendExtraJsonService;

    @Autowired
    private ICompanyAdditionalFieldsService companyAdditionalFieldsService;


    @Override
    public AttendanceSheetResultVO calculateSalaryByAttendPunch(AttendanceSheetResultVO attendanceSheetResultVO, TokenUser tokenUser) {
        //所有人的考勤列表
        List<Map<String, String>> attendList = attendanceSheetResultVO.getAttendList();
        //考勤的工种名字、工资、是否工资项
        Map<String, Map<Double, Integer>> attendFiledInfo = attendanceSheetResultVO.getAttendFiledInfo();
        LinkedHashMap<String, Double> attendSalaryMap = new LinkedHashMap<>();
        double salary = 0.0;
        double wageOfTypeOfWork = 0.0;
        int salaryStatus = 0;
        Double days = 0.0;
        String name = null;
        //每个人的考勤
        for (Map<String, String> stringMap : attendList) {
            //得到名字
            name = stringMap.get("name");
            salary = 0.0;
            //每个人的所有工种名
            for (String stringMapKey : stringMap.keySet()) {
                //排除名字，剩下的都是工种名
                if (!stringMapKey.equals("name")) {
                    //所有工种的每个工种的名字
                    for (String attendFiledInfoKey : attendFiledInfo.keySet()) {
                        //判断这个人的考勤工种在所有工种中有没有被定义
                        if (stringMapKey.equals(attendFiledInfoKey)) {
                            //把工种工资和工资项状态拿出来
                            Map<Double, Integer> doubleIntegerMap = attendFiledInfo.get(attendFiledInfoKey);
                            if (doubleIntegerMap.size() > 0) {
                                for (Map.Entry<Double, Integer> doubleIntegerEntry : doubleIntegerMap.entrySet()) {
                                    wageOfTypeOfWork = doubleIntegerEntry.getKey();
                                    salaryStatus = doubleIntegerEntry.getValue();
                                    break;
                                }
                            }
                            //工种天数
                            days = 0.0;
                            days = Double.parseDouble(stringMap.get(stringMapKey));
                            //工种工资加入到个人工资中
                            salary = salary + wageOfTypeOfWork * salaryStatus * days;
                        }
                    }
                }
            }
            attendSalaryMap.put(name, salary);
        }
        attendanceSheetResultVO.setAttendSalaryMap(attendSalaryMap);
        return attendanceSheetResultVO;
    }

    @Override
    public AttendanceSheetResultVO parseExcelAttendanceSheet(MultipartFile file, TokenUser tokenUser, Integer startCol, Integer endCol, Integer nameCol, Integer startRow) {
        AttendPunchNoModelDataListener attendPunchNoModelDataListener = new AttendPunchNoModelDataListener();
        attendPunchNoModelDataListener.setScanInfo(startCol, endCol, nameCol, startRow);
        try {
            EasyExcel.read(file.getInputStream(), attendPunchNoModelDataListener).sheet().doRead();
        } catch (Exception e) {
            new HrException("文件上传失败");
        }
        return null;
        // return new AttendanceSheetResultVO(attendPunchNoModelDataListener.getList(),attendPunchNoModelDataListener.getAllFieldMap(),new LinkedHashMap<String,Double>());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public AttendPunchRecordVO save(AttendPunchRecordAddDTO attendPunchRecordAddDTO, TokenUser tokenUser) {
        // 转DO
        AttendPunchRecordDO attendPunchRecordDO = attendPunchRecordAddDTO.to(AttendPunchRecordDO.class);
        // 保存
        attendPunchRecordDO = save(attendPunchRecordDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return attendPunchRecordDO.to(AttendPunchRecordVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<AttendPunchRecordVO> batchSave(List<AttendPunchRecordAddDTO> attendPunchRecordAddDTOList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(attendPunchRecordAddDTOList)) {
            return null;
        }
        List<AttendPunchRecordDO> attendPunchRecordDOList = attendPunchRecordAddDTOList
                .parallelStream()
                .map(attendPunchRecordAddDTO -> {
                    AttendPunchRecordDO attendPunchRecordDO = attendPunchRecordAddDTO.to(AttendPunchRecordDO.class);
                    attendPunchRecordDO.preInsert(tokenUser.getUserId());
                    attendPunchRecordDO.setSiteId(tokenUser.getSiteId());
                    return attendPunchRecordDO;
                }).collect(Collectors.toList());
        attendPunchRecordDAO.insertListAndSetId(attendPunchRecordDOList);
        return attendPunchRecordDOList
                .parallelStream()
                .map(attendPunchRecordDO -> attendPunchRecordDO.to(AttendPunchRecordVO.class))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(AttendPunchRecordUpdateDTO attendPunchRecordUpdateDTO, TokenUser tokenUser) {
        //转DO
        AttendPunchRecordDO attendPunchRecordDO = attendPunchRecordUpdateDTO.to(AttendPunchRecordDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(attendPunchRecordDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... attendPunchRecordIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) attendPunchRecordIds);
    }


    @Override
    public AttendPunchRecordVO selectById(String attendPunchRecordId, String siteId) {
        AttendPunchRecordDO attendPunchRecordDO = selectDOById(attendPunchRecordId, siteId);
        if (attendPunchRecordDO == null) {
            return null;
        }
        return attendPunchRecordDO.to(AttendPunchRecordVO.class);
    }

    @Override
    public List<AttendPunchRecordListVO> select(AttendPunchRecordQuery attendPunchRecordQuery, String siteId) {
        List<AttendPunchRecordDO> attendPunchRecordDOList = selectDO(attendPunchRecordQuery, siteId);
        if (CollectionUtils.isEmpty(attendPunchRecordDOList)) {
            return attendPunchRecordDOList == null ? null : new ArrayList<>();
        }
        return attendPunchRecordDOList.stream()
                .map(attendPunchRecordDO -> attendPunchRecordDO.to(AttendPunchRecordListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(AttendPunchRecordQuery attendPunchRecordQuery, String siteId) {
        Example example = buildExample(attendPunchRecordQuery, siteId);
        return attendPunchRecordDAO.selectCountByExample(example);
    }

    @Override
    public Page<AttendPunchRecordListVO> selectPage(AttendPunchRecordQuery attendPunchRecordQuery, String siteId) {
        Example example = buildExample(attendPunchRecordQuery, siteId);
        Page<AttendPunchRecordDO> page = attendPunchRecordDAO.selectPageByExample(example,
                attendPunchRecordQuery.getPageNo(),
                attendPunchRecordQuery.getPageSize());

        return page.to(AttendPunchRecordListVO.class);
    }

    @Override
    public AttendPunchRecordDO selectDOById(String attendPunchRecordId, String siteId) {
        return listById(attendPunchRecordId, siteId);
    }

    @Override
    public List<AttendPunchRecordDO> selectDO(AttendPunchRecordQuery attendPunchRecordQuery, String siteId) {
        Example example = buildExample(attendPunchRecordQuery, siteId);
        return attendPunchRecordDAO.selectByExample(example);
    }


    @Override
    public AttendPunchRecordDO selectOnWorkRecord(String attendPlanId, Integer status, String empInfoId, String attendDateStr, String siteId) {

        // 年
        String yearly = attendDateStr.split("-")[0];
        // 月
        String monthly = attendDateStr.split("-")[1];
        // 日
        String daily = attendDateStr.split("-")[2];

        // 当前是上班打卡还是下班打卡
        // 查询上班打卡记录
        AttendPunchRecordQuery attendPunchRecordQuery = new AttendPunchRecordQuery();
        attendPunchRecordQuery.setAttendPlanId(attendPlanId);
        attendPunchRecordQuery.setEmpInfoId(empInfoId);
        attendPunchRecordQuery.setYear(yearly);
        attendPunchRecordQuery.setMonth(monthly);
        attendPunchRecordQuery.setDay(daily);

        // 打卡类型 ; 0-无效打卡,1-上班打卡,2-下班打卡
        attendPunchRecordQuery.setPunchType(1);
        // 打卡状态 ; 0-缺卡,1-正常,2-迟到,3-早退
        if (status != null) {
            attendPunchRecordQuery.setNotEqPunchStatus(status);
        }
        List<AttendPunchRecordDO> onWorkRecord = this.selectDO(attendPunchRecordQuery, siteId);

        if (onWorkRecord.size() <= 0) {
            return null;
        } else if (onWorkRecord.size() != 1) {
            return null;
        } else {
            return onWorkRecord.get(0);
        }
    }


    @Override
    public AttendPunchRecordDO selectOffWorkRecord(String attendPlanId, Integer status, String empInfoId, String attendDateStr, String siteId) {

        // 年
        String yearly = attendDateStr.split("-")[0];
        // 月
        String monthly = attendDateStr.split("-")[1];
        // 日
        String daily = attendDateStr.split("-")[2];

        // 当前是上班打卡还是下班打卡
        // 查询上班打卡记录
        AttendPunchRecordQuery attendPunchRecordQuery = new AttendPunchRecordQuery();
        attendPunchRecordQuery.setAttendPlanId(attendPlanId);
        attendPunchRecordQuery.setEmpInfoId(empInfoId);
        attendPunchRecordQuery.setYear(yearly);
        attendPunchRecordQuery.setMonth(monthly);
        attendPunchRecordQuery.setDay(daily);

        // 打卡类型 ; 0-无效打卡,1-上班打卡,2-下班打卡
        attendPunchRecordQuery.setPunchType(2);
        if (status != null) {
            attendPunchRecordQuery.setNotEqPunchStatus(status);
        }
        List<AttendPunchRecordDO> onWorkRecord = this.selectDO(attendPunchRecordQuery, siteId);

        if (onWorkRecord.size() <= 0) {
            return null;
        } else if (onWorkRecord.size() != 1) {
            return null;
        } else {
            return onWorkRecord.get(0);
        }
    }

    @Override
    public int saveExcelDataList(List<AttendPunchRecordImportDTO> list, TokenUser tokenUser) {

        // 查询当前用户所在的公司
        String companyId = "";
        EmpInfoQuery empInfoQuery = new EmpInfoQuery();
        empInfoQuery.setUserId(tokenUser.getUserId());
        List<EmpInfoDO> empInfoList = empInfoService.selectDO(empInfoQuery, tokenUser);
        if (empInfoList.size() > 0) {
            companyId = empInfoList.get(0).getCompanyId();
        }

        for (AttendPunchRecordImportDTO record : list) {

            // 根据员工姓名和手机号查询员工信息
            EmpInfoDO empInfo = null;
            EmpInfoQuery empInfoQuer = new EmpInfoQuery();
            // empInfoQuer.setCompanyId(companyId);
            empInfoQuer.setName(record.getEmpInfoName());
            empInfoQuer.setPhone(record.getPhone());
            List<EmpInfoDO> empInfoDOList = empInfoService.selectDO(empInfoQuer, tokenUser);
            if (empInfoDOList.size() > 0) {
                empInfo = empInfoDOList.get(0);
            }

            // 查询当前用户使用的考勤规则
            AttendPlanDO attendPlanDO = null;
            List<AttendPlanDO> attendPlanDOList = attendPlanService.getAttendPlan(empInfo.getId(), record.getAttendDate(), tokenUser.getSiteId());
            if (attendPlanDOList.size() > 0) {
                attendPlanDO = attendPlanDOList.get(0);
            }

            // 上班-公共考勤
            PunchCommonDTO onWork = new PunchCommonDTO();
            onWork.setAttendPlanId(attendPlanDO.getId());
            onWork.setPlanType(attendPlanDO.getPlanType());
            onWork.setEmpInfoId(empInfo.getId());
            onWork.setAttendDateStr(record.getAttendDate());
            onWork.setPunchTimeStr(record.getOnWorkTime());
            PunchCommonVO onWorkVO = attendPunchCommonService.punchCommon(onWork, tokenUser);
            // 保存考勤记录
            this.saveAttendPunchRecord(empInfo, attendPlanDO, record.getAttendDate(), onWorkVO, tokenUser);

            // 下班-公共考勤
            PunchCommonDTO offWork = new PunchCommonDTO();
            offWork.setAttendPlanId(attendPlanDO.getId());
            offWork.setPlanType(attendPlanDO.getPlanType());
            offWork.setEmpInfoId(empInfo.getId());
            offWork.setAttendDateStr(record.getAttendDate());
            offWork.setPunchTimeStr(record.getOnWorkTime());
            PunchCommonVO offWorkVO = attendPunchCommonService.punchCommon(offWork, tokenUser);
            // 保存考勤记录
            this.saveAttendPunchRecord(empInfo, attendPlanDO, record.getAttendDate(), offWorkVO, tokenUser);
        }

        return list.size();
    }

    private void saveAttendPunchRecord(EmpInfoDO empInfo, AttendPlanDO attendPlanDO, String attendDate, PunchCommonVO punchCommonVO, TokenUser tokenUser) {

        AttendPunchRecordAddDTO punchRecord = new AttendPunchRecordAddDTO();
        // 公司ID
        punchRecord.setCompanyId(attendPlanDO.getCompanyId());
        // 公司名称
        punchRecord.setCompanyName(attendPlanDO.getCompanyName());
        // 部门ID
        punchRecord.setDeptId("");
        // 部门名称
        punchRecord.setDeptName("");
        // 员工ID
        punchRecord.setEmpInfoId(empInfo.getId());
        // 员工姓名
        punchRecord.setEmpInfoName(empInfo.getName());
        // 考勤方案
        punchRecord.setAttendPlanId(attendPlanDO.getId());
        // 考勤方案名称
        punchRecord.setAttendPlanName(attendPlanDO.getName());
        // 年
        punchRecord.setYear(attendDate.split("-")[0]);
        // 月
        punchRecord.setMonth(attendDate.split("-")[1]);
        // 日
        punchRecord.setDay(attendDate.split("-")[2]);
        // 打卡类型 ; 0-缺卡,1-上班打卡,2-下班打卡
        punchRecord.setPunchType(1);

        // 上班
        if (punchCommonVO.getWorkStatus() == 1) {
            // 标准时间
//            punchRecord.setStandardTime(punchCommonVO.getOnWorkTime());
            // 打卡时间(HH:mm)
//            punchRecord.setPunchTime(punchCommonVO.getOnWorkPunchTime());
        }
        // 下班
        else if (punchCommonVO.getWorkStatus() == 2) {
            // 标准时间
//            punchRecord.setStandardTime(punchCommonVO.getOffWorkTime());
            // 打卡时间(HH:mm)
//            punchRecord.setPunchTime(punchCommonVO.getOffWorkPunchTime());
        } else {
            // 标准时间
            punchRecord.setStandardTime(null);
            // 打卡时间(HH:mm)
            punchRecord.setPunchTime(null);
            // 无效打卡
            punchRecord.setPunchType(0);
        }
        // 打卡状态 ; 0-缺卡,1-正常,2-迟到,3-早退
        punchRecord.setPunchStatus(punchCommonVO.getPunchStatus());
        // 迟到/早退分钟数
        punchRecord.setMinute(punchCommonVO.getMinutes());
        punchRecord.setDecisionDesc("");
        // 打卡坐标
        punchRecord.setCoordinate("");
        // 打卡地点
        punchRecord.setLocation("");
        // 打卡wifi
        punchRecord.setPunchWifi("");
        // 打卡来源 ; 1-app打卡,2-考勤机打卡
        punchRecord.setPunchSource(3);
        // 是否补卡 ; 1-是,0-否
        punchRecord.setIsMakeUp(false);

        this.save(punchRecord, tokenUser);
    }


    @Override
    public List<AttendPunchRecordExportVO> selectExportList(AttendPunchRecordQuery attendPunchRecordQuery, String siteId) {
        int count = selectCount(attendPunchRecordQuery, siteId);
        if (count > 10000) {
            throw new ParamException("一次最多导出10000条数据，请缩小检索范围");
        }
        List<AttendPunchRecordDO> attendPunchRecordDOList = selectDO(attendPunchRecordQuery, siteId);
        if (CollectionUtils.isEmpty(attendPunchRecordDOList)) {
            return new ArrayList<>();
        }
        return attendPunchRecordDOList.stream()
                .map(attendPunchRecordDO -> attendPunchRecordDO.to(AttendPunchRecordExportVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public List<ParseResultVO<AttendPunchRecordImportDTO>> parseImportFile(File file, Boolean success, TokenUser tokenUser) {
        AttendPunchRecordImportListener attendPunchRecordImportListener = new AttendPunchRecordImportListener();
        attendPunchRecordImportListener.setTokenUser(tokenUser);
        attendPunchRecordImportListener.setParseOnly(true);
        // 读取excel 只解析不入库
        EasyExcel.read(file, AttendPunchRecordImportDTO.class, attendPunchRecordImportListener).sheet().doRead();
        if (success == null) {
            return attendPunchRecordImportListener.getParseResultList();
        } else {
            return attendPunchRecordImportListener.getParseResultList()
                    .stream()
                    .filter(parseResult -> success.equals(parseResult.getSuccess()))
                    .collect(Collectors.toList());
        }
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Integer importFile(File file, TokenUser tokenUser, Boolean force) {
        AttendPunchRecordImportListener attendPunchRecordImportListener = new AttendPunchRecordImportListener();
        attendPunchRecordImportListener.setTokenUser(tokenUser);
        attendPunchRecordImportListener.setForce(force);
        // 读取excel 并且入库
        EasyExcel.read(file, AttendPunchRecordImportDTO.class, attendPunchRecordImportListener).sheet().doRead();
        return attendPunchRecordImportListener.getSuccessCount();
    }

    @Override
    public Page<AttendPunchRecordVO> selectAttendPunchRecord(TokenUser tokenUser, AttendPunchRecordQuery attendPunchRecordQuery) {
        if (this.checkYearAndMonthAndCompanyId(attendPunchRecordQuery)) {
            throw new ParamException("必填参数未传");
        }
        List<String> attendPlanId = new ArrayList<>();
        Set<String> attendPlanIdSet = new HashSet<>();
        PageInfo<AttendPunchRecordVO> pageInfoAll =
                PageHelper.startPage(attendPunchRecordQuery.getPageNo(),
                        attendPunchRecordQuery.getPageSize()).doSelectPageInfo(() ->
                        attendPunchRecordDAO.selectAttendPunchRecord(attendPunchRecordQuery, tokenUser.getSiteId())
                                .forEach(attendPunchRecordVO -> {
                                    if (attendPunchRecordVO.getNormalDay() != null && attendPunchRecordVO.getUnusualDay() != null) {
                                        attendPunchRecordVO.setNormalDay(attendPunchRecordVO.getNormalDay() - attendPunchRecordVO.getUnusualDay());
                                    }
                                    if (attendPunchRecordVO.getBeLateTime() == null) {
                                        attendPunchRecordVO.setBeLateTime(0);
                                    }
                                    if (attendPunchRecordVO.getLeaveEarlyTime() == null) {
                                        attendPunchRecordVO.setLeaveEarlyTime(0);
                                    }
                                    if (!StringUtils.isEmpty(attendPunchRecordVO.getEmpInfoId())) {
                                        List<AttendPunchRecordVO> attendPunchRecordVOS =
                                                attendPunchRecordDAO.selectLeaveEarly(attendPunchRecordQuery,
                                                        attendPunchRecordVO.getEmpInfoId(), tokenUser.getSiteId());
                                        if (!CollectionUtils.isEmpty(attendPunchRecordVOS) && attendPunchRecordVOS.get(0) != null) {
                                            Integer leaveEarlyCount = attendPunchRecordVOS.get(0).getLeaveEarlyCount() == null ?
                                                    0 : attendPunchRecordVOS.get(0).getLeaveEarlyCount();
                                            attendPunchRecordVO.setLeaveEarlyCount(leaveEarlyCount);
                                            Integer leaveEarlyTime = attendPunchRecordVOS.get(0).getLeaveEarlyTime() == null ?
                                                    0 : attendPunchRecordVOS.get(0).getLeaveEarlyTime();
                                            attendPunchRecordVO.setLeaveEarlyTime(leaveEarlyTime);
                                            attendPunchRecordVO.setUnusualCount(attendPunchRecordVO.getUnusualCount() + attendPunchRecordVOS.get(0).getLeaveEarlyCount());
                                            attendPunchRecordVO.setWorkDate(this.workTime(attendPunchRecordVOS.get(0).getWorkTime()));
                                        } else {
                                            attendPunchRecordVO.setLeaveEarlyCount(0);
                                            attendPunchRecordVO.setLeaveEarlyTime(0);
                                            attendPunchRecordVO.setWorkDate(this.workTime(null));
                                        }
                                    }
                                    attendPlanId.add(attendPunchRecordVO.getAttendPlanId());
                                    attendPlanIdSet.add(attendPunchRecordVO.getAttendPlanId());
                                }));
        //查询方案所对应的应打卡天数
        PageInfo<AttendPunchRecordVO> pageInfo =
                this.shouldDatCount(attendPlanIdSet, attendPunchRecordQuery, tokenUser, pageInfoAll);
        Page<AttendPunchRecordVO> page =
                new Page<>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal());
        return page.to(AttendPunchRecordVO.class);
    }

    @Override
    public Page<AttendPunchRecordVO> selectAttendMonth(AttendPunchRecordQuery attendPunchRecordQuery, TokenUser tokenUser) {
        if (this.checkYearAndMonthAndCompanyId(attendPunchRecordQuery)
                || StringUtils.isEmpty(attendPunchRecordQuery.getEmpInfoId())) {
            throw new ParamException("必填参数未传");
        }
        List<String> attendPlanId = new ArrayList<>();
        Set<String> attendPlanIdSet = new HashSet<>();
        PageInfo<AttendPunchRecordVO> pageInfoAll =
                PageHelper.startPage(attendPunchRecordQuery.getPageNo(),
                        attendPunchRecordQuery.getPageSize()).doSelectPageInfo(() ->
                        attendPunchRecordDAO.selectAttendMonth(attendPunchRecordQuery, tokenUser.getSiteId())
                                .forEach(attendBean -> {
                                    AttendPunchRecordVO attendPunchRecordVO =
                                            this.arriveAndLeave2(attendBean.getOrderByArrive(),
                                                    attendBean.getOrderByLeave(), attendBean.getCalibration());
                                    if (attendPunchRecordVO != null) {
                                        // 如果上班集合都有时间  则按照时间排序
                                        if (attendPunchRecordVO.getArriveList() != null) {
                                            List<AttendPunchRecordArriveListVO> attendPunchRecordArriveListVOS
                                                    = attendPunchRecordVO.getArriveList();
                                            AtomicBoolean sort = new AtomicBoolean(true);
                                            attendPunchRecordArriveListVOS.forEach(attendPunchRecordArriveListVO -> {
                                                if (StrKit.isEmpty(attendPunchRecordArriveListVO.getArriveTime())) {
                                                    sort.set(false);
                                                }
                                            });
                                            if (sort.get()) {
                                                Collections.sort(attendPunchRecordArriveListVOS);
                                            }
                                        }
                                        // 如果下班集合都有时间  则按照时间排序
                                        if (attendPunchRecordVO.getLeaveList() != null) {
                                            List<AttendPunchRecordLeaveListVO> attendPunchRecordLeaveListVOList
                                                    = attendPunchRecordVO.getLeaveList();
                                            AtomicBoolean sort = new AtomicBoolean(true);
                                            attendPunchRecordLeaveListVOList.forEach(attendPunchRecordLeaveListVO -> {
                                                if (StrKit.isEmpty(attendPunchRecordLeaveListVO.getLeaveTime())) {
                                                    sort.set(false);
                                                }
                                            });
                                            if (sort.get()) {
                                                Collections.sort(attendPunchRecordLeaveListVOList);
                                            } else {
                                                Collections.reverse(attendPunchRecordVO.getLeaveList());
                                            }
                                        }
                                        if (attendPunchRecordVO.getArriveList().size() > 1) {
                                            attendBean.setArriveOne(attendPunchRecordVO.getArriveList().get(0));
                                            attendBean.setArriveTwo(attendPunchRecordVO.getArriveList().get(1));
                                        } else if (attendPunchRecordVO.getArriveList().size() == 1) {
                                            attendBean.setArriveOne(attendPunchRecordVO.getArriveList().get(0));
                                        }
                                        if (attendPunchRecordVO.getLeaveList().size() > 1) {
                                            if (attendPunchRecordVO.getArriveList().size() > 1) {
                                                // 如果有两条上班卡记录
                                                String arriveTime = attendPunchRecordVO.getArriveList().get(1).getArriveTime();
                                                // 找到第一次上班到第二次上班的时间段中最后的一次下班打卡记录
                                                AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO = attendPunchRecordVO.getLeaveList().get(0);
                                                AttendPunchRecordLeaveListVO attendPunchRecordLeaveListLeave;
                                                if ("下班缺卡".equals(attendPunchRecordVO.getLeaveList().get(1).getLeaveStatus())) {
                                                    attendPunchRecordLeaveListLeave = attendPunchRecordVO.getLeaveList().get(1);
                                                } else {
                                                    attendPunchRecordLeaveListLeave = new AttendPunchRecordLeaveListVO();
                                                }
                                                for (int i = 0; i < attendPunchRecordVO.getLeaveList().size(); i++) {
                                                    String leaveTime = attendPunchRecordVO.getLeaveList().get(i).getLeaveTime();
                                                    String leaveTimeReturn = attendPunchRecordLeaveListVO.getLeaveTime();
                                                    if (StrKit.isEmpty(arriveTime) || StrKit.isEmpty(leaveTime)) {
                                                        continue;
                                                    }
                                                    if (DateKit8.parseDateTime(leaveTime).getTime() <
                                                            DateKit8.parseDateTime(arriveTime).getTime()) {
                                                        if (DateKit8.parseDateTime(leaveTimeReturn).getTime() <=
                                                                DateKit8.parseDateTime(leaveTime).getTime()) {
                                                            attendPunchRecordLeaveListVO = attendPunchRecordVO.getLeaveList().get(i);
                                                        }
                                                    } else {
                                                        attendPunchRecordLeaveListLeave = attendPunchRecordVO.getLeaveList().get(i);
                                                    }
                                                }
                                                attendBean.setLeaveOne(attendPunchRecordLeaveListVO);
                                                // 第二次下班卡为最后一条记录
                                                attendBean.setLeaveTwo(attendPunchRecordLeaveListLeave);
                                            } else {
                                                // 如果只有一次上班卡记录  下班卡记录取最后一条
                                                attendBean.setLeaveOne(attendPunchRecordVO.getLeaveList().get(attendPunchRecordVO.getLeaveList().size() - 1));
                                            }
                                        } else if (!CollectionUtils.isEmpty(attendPunchRecordVO.getLeaveList())
                                                && !CollectionUtils.isEmpty(attendPunchRecordVO.getArriveList())) {
                                            attendBean.setLeaveOne(attendPunchRecordVO.getLeaveList().get(0));
                                        }
                                        attendBean.setArriveList(attendPunchRecordVO.getArriveList());
                                        attendBean.setLeaveList(attendPunchRecordVO.getLeaveList());
                                        attendBean.setIsCalibrationArrive(attendPunchRecordVO.getIsCalibrationArrive());
                                        attendBean.setIsCalibrationLeave(attendPunchRecordVO.getIsCalibrationLeave());
                                        attendBean.setWorkDate(this.workTime(attendBean.getWorkTime()));
                                    }
                                    if (attendBean.getNormalDay() != null && attendBean.getUnusualDay() != null) {
                                        attendBean.setCount(attendBean.getNormalDay() - attendBean.getUnusualDay());
                                    }
                                    attendPlanId.add(attendBean.getAttendPlanId());
                                    attendPlanIdSet.add(attendBean.getAttendPlanId());
                                }));
        //查询方案所对应的应打卡天数
        PageInfo<AttendPunchRecordVO> pageInfo =
                this.shouldDatCount(attendPlanIdSet, attendPunchRecordQuery, tokenUser, pageInfoAll);
        // 去掉月份的0
        pageInfo.getList().forEach(attendPunchRecordVO -> {
            if (StrKit.isNotEmpty(attendPunchRecordVO.getTimeDay())) {
                String[] yearAndMonthAndDay = attendPunchRecordVO.getTimeDay().split("-");
                StringBuilder ymd = new StringBuilder();
                if (yearAndMonthAndDay.length > 2) {
                    if (!"10".equals(yearAndMonthAndDay[1])) {
                        yearAndMonthAndDay[1] = yearAndMonthAndDay[1].replaceAll("0", "");
                    }
                }
                for (String s : yearAndMonthAndDay) {
                    ymd.append(s).append("-");
                }
                attendPunchRecordVO.setTimeDay(ymd.substring(0, ymd.length() - 1));
            }
        });
        Page<AttendPunchRecordVO> page =
                new Page<>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal());
        return page.to(AttendPunchRecordVO.class);
    }

    @Override
    public List<AttendPunchRecordVO> selectAttendYearMonth(AttendPunchRecordQuery attendPunchRecordQuery, TokenUser tokenUser) {
        // 查询员工信息
        EmpInfoQuery empInfoQuery = new EmpInfoQuery();
        empInfoQuery.setUserId(tokenUser.getUserId());
        List<EmpInfoDO> empInfoList = empInfoService.selectDO(empInfoQuery, tokenUser);
        if (empInfoList.size() <= 0) {
            throw new HrException("用户信息不存在");
        }
        attendPunchRecordQuery.setEmpInfoId(empInfoList.get(0).getId());
        List<AttendPunchRecordVO> attendPunchRecordVOList = attendPunchRecordDAO
                .selectAttendYearMonth(attendPunchRecordQuery, tokenUser.getSiteId());
        attendPunchRecordVOList.forEach(attendPunchRecordVO -> {
            Integer offStatus = attendPunchRecordVO.getOffStatus();
            Integer onStatus = attendPunchRecordVO.getOnStatus();
            if (offStatus == null || onStatus == null) {
                attendPunchRecordVO.setPunchDayStatus(0);
            } else {
                attendPunchRecordVO.setPunchDayStatus(offStatus == 1 && onStatus == 1 ? 1 : 0);
            }
        });
        return attendPunchRecordVOList;
    }

    @Override
    public void setShouldDatCount(List<AttendPunchRecordVO> attendPunchRecordVOList,
                                  String year, String month, TokenUser tokenUser) {
        List<String> planIdList = attendPunchRecordVOList.stream()
                .map(AttendPunchRecordVO::getAttendPlanId)
                .collect(Collectors.toList());
        //查询方案所对应的应打卡天数
        Map<String, Integer> punchEmpMonthCountDTOMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(planIdList)) {
            String time = year + "-" + month;
            punchEmpMonthCountDTOMap = this.getPunchEmpMonthCountDTOList(planIdList, time, tokenUser);
        }
        for (AttendPunchRecordVO attendPunchRecordVO : attendPunchRecordVOList) {
            attendPunchRecordVO.setShouldDayCount(punchEmpMonthCountDTOMap.get(attendPunchRecordVO.getAttendPlanId()) == null ?
                    0 : punchEmpMonthCountDTOMap.get(attendPunchRecordVO.getAttendPlanId()));
        }
    }

    /**
     * 查询应打卡天数
     *
     * @param attendPlanIdSet        方案id的集合
     * @param attendPunchRecordQuery 年月条件
     * @param tokenUser              当前用户信息
     * @param pageInfo               结果集
     * @return 处理好的结果集
     */
    private PageInfo<AttendPunchRecordVO> shouldDatCount(Set<String> attendPlanIdSet, AttendPunchRecordQuery attendPunchRecordQuery,
                                                         TokenUser tokenUser, PageInfo<AttendPunchRecordVO> pageInfo) {
        List<String> attendPlanIdList = new ArrayList<>();
        attendPlanIdList.addAll(attendPlanIdSet);
        //查询方案所对应的应打卡天数
        Map<String, Integer> punchEmpMonthCountDTOMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(attendPlanIdSet)) {
            String time = attendPunchRecordQuery.getYear() + "-" + attendPunchRecordQuery.getMonth();
            punchEmpMonthCountDTOMap = this.getPunchEmpMonthCountDTOList(attendPlanIdList, time, tokenUser);
        }
        if (!CollectionUtils.isEmpty(punchEmpMonthCountDTOMap)) {
            for (AttendPunchRecordVO attendPunchRecordVO : pageInfo.getList()) {
                attendPunchRecordVO.setShouldDayCount(punchEmpMonthCountDTOMap.get(attendPunchRecordVO.getAttendPlanId()));
            }
        }
        return pageInfo;
    }

    /**
     * 对年，月，公司id必填项校验
     *
     * @param attendPunchRecordQuery 参数bean
     * @return 返回校验结果
     */
    private Boolean checkYearAndMonthAndCompanyId(AttendPunchRecordQuery attendPunchRecordQuery) {
        if (StringUtils.isEmpty(attendPunchRecordQuery.getCompanyId())
                || StringUtils.isEmpty(attendPunchRecordQuery.getYear())
                || StringUtils.isEmpty(attendPunchRecordQuery.getMonth())) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 将时间封装成显示格式
     *
     * @param time 分钟数
     * @return 返回结果
     */
    private String workTime(Integer time) {
        if (time == null) {
            return "0小时0分钟";
        }
        int hours = (int) Math.floor(Math.abs(time) / 60);
        int minute = time % 60;
        return hours + "小时" + minute + "分钟";
    }

    @Override
    public Page<AttendPunchRecordVO> selectAttendByDay(AttendPunchRecordQuery attendPunchRecordQuery, TokenUser tokenUser) {
        if (StringUtils.isEmpty(attendPunchRecordQuery.getCompanyId())
                || StringUtils.isEmpty(attendPunchRecordQuery.getAttendStart())
                || StringUtils.isEmpty(attendPunchRecordQuery.getAttendEnd())) {
            throw new ParamException("必填参数未传");
        }
        // 开启循环模式
        List<Date> dateList = new ArrayList<>();
        Date startDate = DateKit8.parseDate(attendPunchRecordQuery.getAttendStart());
        Date endDate = DateKit8.parseDate(attendPunchRecordQuery.getAttendEnd());
        while (startDate.getTime() <= endDate.getTime()) {
            dateList.add(startDate);
            startDate = DateKit8.addDays(startDate, 1);
        }
        List<AttendPunchRecordVO> attendPunchRecordAll = new ArrayList<>();
        for (Date date : dateList) {
            List<String> dateStr = ArrayKit.split(DateKit8.format2Date(date), "-");
            if (dateStr.size() < 3) {
                throw new ParamException("时间转换异常，请联系管理员或稍后重试!");
            }
            attendPunchRecordQuery.setYear(dateStr.get(0));
            attendPunchRecordQuery.setMonth(dateStr.get(1));
            attendPunchRecordQuery.setDay(dateStr.get(2));
            // 根据时间判断  2021年8月21日之后的数据 工作时长求和
            Date limitDate = DateKit8.parseDate("2021-08-21 00:00:00");
            List<AttendPunchRecordVO> attendPunchRecordVOList;
            if (date.getTime() > limitDate.getTime()) {
                // 新数据 求和
                attendPunchRecordVOList = attendPunchRecordDAO
                        .selectAttendByDay(attendPunchRecordQuery, tokenUser.getSiteId());
            } else {
                // 取最后一条
                attendPunchRecordVOList = attendPunchRecordDAO
                        .selectAttendByDayTwo(attendPunchRecordQuery, tokenUser.getSiteId());
            }
            if (!CollectionUtils.isEmpty(attendPunchRecordVOList)) {
                attendPunchRecordAll.addAll(attendPunchRecordVOList);
            }
        }
        attendPunchRecordAll.forEach(attendBean -> {
            AttendPunchRecordVO attendPunchRecordVO =
                    this.arriveAndLeave2(attendBean.getOrderByArrive(),
                            attendBean.getOrderByLeave(), attendBean.getCalibration());
            if (attendPunchRecordVO != null) {
                // 如果上班集合都有时间  则按照时间排序
                if (attendPunchRecordVO.getArriveList() != null) {
                    List<AttendPunchRecordArriveListVO> attendPunchRecordArriveListVOS
                            = attendPunchRecordVO.getArriveList();
                    AtomicBoolean sort = new AtomicBoolean(true);
                    attendPunchRecordArriveListVOS.forEach(attendPunchRecordArriveListVO -> {
                        if (StrKit.isEmpty(attendPunchRecordArriveListVO.getArriveTime())) {
                            sort.set(false);
                        }
                    });
                    if (sort.get()) {
                        Collections.sort(attendPunchRecordArriveListVOS);
                    }
                }
                // 如果下班集合都有时间  则按照时间排序
                if (attendPunchRecordVO.getLeaveList() != null) {
                    List<AttendPunchRecordLeaveListVO> attendPunchRecordLeaveListVOList
                            = attendPunchRecordVO.getLeaveList();
                    AtomicBoolean sort = new AtomicBoolean(true);
                    attendPunchRecordLeaveListVOList.forEach(attendPunchRecordLeaveListVO -> {
                        if (StrKit.isEmpty(attendPunchRecordLeaveListVO.getLeaveTime())) {
                            sort.set(false);
                        }
                    });
                    if (sort.get()) {
                        Collections.sort(attendPunchRecordLeaveListVOList);
                    } else {
                        Collections.reverse(attendPunchRecordVO.getLeaveList());
                    }
                }
                attendBean.setArriveList(attendPunchRecordVO.getArriveList());
                attendBean.setLeaveList(attendPunchRecordVO.getLeaveList());
                if (attendPunchRecordVO.getArriveList().size() > 1) {
                    attendBean.setArriveOne(attendPunchRecordVO.getArriveList().get(0));
                    attendBean.setArriveTwo(attendPunchRecordVO.getArriveList().get(1));
                } else if (attendPunchRecordVO.getArriveList().size() == 1) {
                    attendBean.setArriveOne(attendPunchRecordVO.getArriveList().get(0));
                }
                if (attendPunchRecordVO.getLeaveList().size() > 1) {
                    if (attendPunchRecordVO.getArriveList().size() > 1) {
                        // 如果有两条上班卡记录
                        String arriveTime = attendPunchRecordVO.getArriveList().get(1).getArriveTime();
                        // 找到第一次上班到第二次上班的时间段中最后的一次下班打卡记录
                        AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO = attendPunchRecordVO.getLeaveList().get(0);
                        AttendPunchRecordLeaveListVO attendPunchRecordLeaveListLeave;
                        if ("下班缺卡".equals(attendPunchRecordVO.getLeaveList().get(1).getLeaveStatus())) {
                            attendPunchRecordLeaveListLeave = attendPunchRecordVO.getLeaveList().get(1);
                        } else {
                            attendPunchRecordLeaveListLeave = new AttendPunchRecordLeaveListVO();
                        }
                        for (int i = 0; i < attendPunchRecordVO.getLeaveList().size(); i++) {
                            String leaveTime = attendPunchRecordVO.getLeaveList().get(i).getLeaveTime();
                            String leaveTimeReturn = attendPunchRecordLeaveListVO.getLeaveTime();
                            if (StrKit.isEmpty(arriveTime) || StrKit.isEmpty(leaveTime)) {
                                continue;
                            }
                            if (DateKit8.parseDateTime(leaveTime).getTime() <
                                    DateKit8.parseDateTime(arriveTime).getTime()) {
                                if (DateKit8.parseDateTime(leaveTimeReturn).getTime() <=
                                        DateKit8.parseDateTime(leaveTime).getTime()) {
                                    attendPunchRecordLeaveListVO = attendPunchRecordVO.getLeaveList().get(i);
                                }
                            } else {
                                attendPunchRecordLeaveListLeave = attendPunchRecordVO.getLeaveList().get(i);
                            }
                        }
                        attendBean.setLeaveOne(attendPunchRecordLeaveListVO);
                        // 第二次下班卡为最后一条记录
                        attendBean.setLeaveTwo(attendPunchRecordLeaveListLeave);
                    } else {
                        // 如果只有一次上班卡记录  下班卡记录取最后一条
                        attendBean.setLeaveOne(attendPunchRecordVO.getLeaveList().get(attendPunchRecordVO.getLeaveList().size() - 1));
                    }
                } else if (!CollectionUtils.isEmpty(attendPunchRecordVO.getLeaveList())
                        && !CollectionUtils.isEmpty(attendPunchRecordVO.getArriveList())) {
                    attendBean.setLeaveOne(attendPunchRecordVO.getLeaveList().get(0));
                }
                attendBean.setIsCalibrationArrive(attendPunchRecordVO.getIsCalibrationArrive());
                attendBean.setIsCalibrationLeave(attendPunchRecordVO.getIsCalibrationLeave());
            }
            attendBean.setWorkDate(this.workTime(attendBean.getWorkTime()));
        });

        //考勤打卡列表表头初始化
        CompanyAdditionalFieldsQuery companyAdditionalFieldsQuery = new CompanyAdditionalFieldsQuery();
        companyAdditionalFieldsQuery.setCompanyId(attendPunchRecordQuery.getCompanyId());
        companyAdditionalFieldsQuery.setModuleCode("考勤打卡列表");
        List<CompanyAdditionalFieldsListVO> select = companyAdditionalFieldsService.select(companyAdditionalFieldsQuery, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(select)) {
            for (int i = 0; i < 13; i++) {
                CompanyAdditionalFieldsAddDTO companyAdditionalFieldsAddDTO = new CompanyAdditionalFieldsAddDTO();
                companyAdditionalFieldsAddDTO.setModuleCode("考勤打卡列表");
                companyAdditionalFieldsAddDTO.setCompanyId(attendPunchRecordQuery.getCompanyId());
                companyAdditionalFieldsAddDTO.setSort(i);
                companyAdditionalFieldsAddDTO.setIsOpen(true);
                companyAdditionalFieldsAddDTO.setIsEdit(1);
                if (i == 0) {
                    companyAdditionalFieldsAddDTO.setIsEdit(0);
                    companyAdditionalFieldsAddDTO.setFieldName("姓名");
                    companyAdditionalFieldsAddDTO.setDescription("empInfoName");
                } else if (i == 1) {
                    companyAdditionalFieldsAddDTO.setFieldName("岗位");
                    companyAdditionalFieldsAddDTO.setDescription("positionName");
                } else if (i == 2) {
                    companyAdditionalFieldsAddDTO.setFieldName("打卡日期");
                    companyAdditionalFieldsAddDTO.setDescription("timeDay");
                } else if (i == 3) {
                    companyAdditionalFieldsAddDTO.setFieldName("考勤规则");
                    companyAdditionalFieldsAddDTO.setDescription("attendPlanName");
                } else if (i == 4) {
                    companyAdditionalFieldsAddDTO.setFieldName("第一次打卡上班时间");
                    companyAdditionalFieldsAddDTO.setDescription("arriveOne.arriveTime");
                } else if (i == 5) {
                    companyAdditionalFieldsAddDTO.setFieldName("第一次打卡上班地点");
                    companyAdditionalFieldsAddDTO.setDescription("arriveOne.arrivePlace");
                } else if (i == 6) {
                    companyAdditionalFieldsAddDTO.setFieldName("第一次打卡下班时间");
                    companyAdditionalFieldsAddDTO.setDescription("leaveOne.leaveTime");
                } else if (i == 7) {
                    companyAdditionalFieldsAddDTO.setFieldName("第一次打卡下班地点");
                    companyAdditionalFieldsAddDTO.setDescription("leaveOne.leavePlace");
                } else if (i == 8) {
                    companyAdditionalFieldsAddDTO.setFieldName("第二次打卡上班时间");
                    companyAdditionalFieldsAddDTO.setDescription("arriveTwo.leavePlace");
                } else if (i == 9) {
                    companyAdditionalFieldsAddDTO.setFieldName("第二次打卡上班地点");
                    companyAdditionalFieldsAddDTO.setDescription("arriveTwo.leavePlace");
                } else if (i == 10) {
                    companyAdditionalFieldsAddDTO.setFieldName("第二次打卡下班时间");
                    companyAdditionalFieldsAddDTO.setDescription("leaveTwo.leavePlace");
                } else if (i == 11) {
                    companyAdditionalFieldsAddDTO.setFieldName("第二次打卡下班地点");
                    companyAdditionalFieldsAddDTO.setDescription("leaveTwo.leavePlace");
                } else {
                    companyAdditionalFieldsAddDTO.setFieldName("工作时长");
                    companyAdditionalFieldsAddDTO.setDescription("workDate");
                }
                companyAdditionalFieldsService.save(companyAdditionalFieldsAddDTO.to(CompanyAdditionalFieldsDO.class), tokenUser.getSiteId(), tokenUser.getUserId());
            }
        }

        Page<AttendPunchRecordVO> page = PageKit.startPage(attendPunchRecordAll,
                attendPunchRecordQuery.getPageNo(), attendPunchRecordQuery.getPageSize());
        return page.to(AttendPunchRecordVO.class);
    }

    @Override
    public Page<AttendPunchRecordVO> selectAttendByTime(AttendPunchRecordQuery attendPunchRecordQuery, TokenUser tokenUser) {
        if (StringUtils.isEmpty(attendPunchRecordQuery.getCompanyId())
                || StringUtils.isEmpty(attendPunchRecordQuery.getAttendStart())
                || StringUtils.isEmpty(attendPunchRecordQuery.getAttendEnd())) {
            throw new ParamException("必填参数未传");
        }
        // 构造查询时间范围
        attendPunchRecordQuery.setStartTime(attendPunchRecordQuery.getAttendStart().replaceAll("-", ""));
        attendPunchRecordQuery.setEndTime(attendPunchRecordQuery.getAttendEnd().replaceAll("-", ""));
        List<AttendPunchRecordVO> returnAttendPunchRecord = new ArrayList<>();
        List<AttendPunchRecordVO> attendPunchRecordAll = attendPunchRecordDAO
                .selectAttendByTime(attendPunchRecordQuery, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(attendPunchRecordAll)) {
            return PageKit.startPage(returnAttendPunchRecord,
                    attendPunchRecordQuery.getPageNo(), attendPunchRecordQuery.getPageSize());
        }
        // 处理考勤记录  构造前端需要展示的信息
        // 根据打卡年分组
        Map<String, List<AttendPunchRecordVO>> attendPunchRecordByYearMap = attendPunchRecordAll
                .stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getYear));
        for (String year : attendPunchRecordByYearMap.keySet()) {
            List<AttendPunchRecordVO> attendPunchRecordYearList = attendPunchRecordByYearMap.get(year);
            // 根据打卡月分组
            Map<String, List<AttendPunchRecordVO>> attendPunchRecordByMonthMap = attendPunchRecordYearList
                    .stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getMonth));
            for (String month : attendPunchRecordByMonthMap.keySet()) {
                List<AttendPunchRecordVO> attendPunchRecordMonthList = attendPunchRecordByMonthMap.get(month);
                // 根据打卡日分组
                Map<String, List<AttendPunchRecordVO>> attendPunchRecordByDayMap = attendPunchRecordMonthList
                        .stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getDay));
                for (String day : attendPunchRecordByDayMap.keySet()) {
                    List<AttendPunchRecordVO> attendPunchRecordDayList = attendPunchRecordByDayMap.get(day);
                    // 根据empInfoId分组
                    Map<String, List<AttendPunchRecordVO>> attendPunchRecordByEmpInfoIdMap = attendPunchRecordDayList
                            .stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getEmpInfoId));
                    for (String empInfoId : attendPunchRecordByEmpInfoIdMap.keySet()) {
                        List<AttendPunchRecordVO> attendPunchRecordEmpInfoIdList = attendPunchRecordByEmpInfoIdMap.get(empInfoId);
                        returnAttendPunchRecord.add(buildReturnAttendPunchRecordVO(attendPunchRecordEmpInfoIdList));
                    }
                }
            }
        }
        //考勤打卡列表表头初始化
        CompanyAdditionalFieldsQuery companyAdditionalFieldsQuery = new CompanyAdditionalFieldsQuery();
        companyAdditionalFieldsQuery.setCompanyId(attendPunchRecordQuery.getCompanyId());
        companyAdditionalFieldsQuery.setModuleCode("考勤打卡列表");
        List<CompanyAdditionalFieldsListVO> select = companyAdditionalFieldsService.select(companyAdditionalFieldsQuery, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(select)) {
            for (int i = 0; i < 13; i++) {
                CompanyAdditionalFieldsAddDTO companyAdditionalFieldsAddDTO = new CompanyAdditionalFieldsAddDTO();
                companyAdditionalFieldsAddDTO.setModuleCode("考勤打卡列表");
                companyAdditionalFieldsAddDTO.setCompanyId(attendPunchRecordQuery.getCompanyId());
                companyAdditionalFieldsAddDTO.setSort(i);
                companyAdditionalFieldsAddDTO.setIsOpen(true);
                companyAdditionalFieldsAddDTO.setIsEdit(1);
                if (i == 0) {
                    companyAdditionalFieldsAddDTO.setIsEdit(0);
                    companyAdditionalFieldsAddDTO.setFieldName("姓名");
                    companyAdditionalFieldsAddDTO.setDescription("empInfoName");
                } else if (i == 1) {
                    companyAdditionalFieldsAddDTO.setFieldName("岗位");
                    companyAdditionalFieldsAddDTO.setDescription("positionName");
                } else if (i == 2) {
                    companyAdditionalFieldsAddDTO.setFieldName("打卡日期");
                    companyAdditionalFieldsAddDTO.setDescription("timeDay");
                } else if (i == 3) {
                    companyAdditionalFieldsAddDTO.setFieldName("考勤规则");
                    companyAdditionalFieldsAddDTO.setDescription("attendPlanName");
                } else if (i == 4) {
                    companyAdditionalFieldsAddDTO.setFieldName("第一次打卡上班时间");
                    companyAdditionalFieldsAddDTO.setDescription("arriveOne.arriveTime");
                } else if (i == 5) {
                    companyAdditionalFieldsAddDTO.setFieldName("第一次打卡上班地点");
                    companyAdditionalFieldsAddDTO.setDescription("arriveOne.arrivePlace");
                } else if (i == 6) {
                    companyAdditionalFieldsAddDTO.setFieldName("第一次打卡下班时间");
                    companyAdditionalFieldsAddDTO.setDescription("leaveOne.leaveTime");
                } else if (i == 7) {
                    companyAdditionalFieldsAddDTO.setFieldName("第一次打卡下班地点");
                    companyAdditionalFieldsAddDTO.setDescription("leaveOne.leavePlace");
                } else if (i == 8) {
                    companyAdditionalFieldsAddDTO.setFieldName("第二次打卡上班时间");
                    companyAdditionalFieldsAddDTO.setDescription("arriveTwo.leavePlace");
                } else if (i == 9) {
                    companyAdditionalFieldsAddDTO.setFieldName("第二次打卡上班地点");
                    companyAdditionalFieldsAddDTO.setDescription("arriveTwo.leavePlace");
                } else if (i == 10) {
                    companyAdditionalFieldsAddDTO.setFieldName("第二次打卡下班时间");
                    companyAdditionalFieldsAddDTO.setDescription("leaveTwo.leavePlace");
                } else if (i == 11) {
                    companyAdditionalFieldsAddDTO.setFieldName("第二次打卡下班地点");
                    companyAdditionalFieldsAddDTO.setDescription("leaveTwo.leavePlace");
                } else {
                    companyAdditionalFieldsAddDTO.setFieldName("工作时长");
                    companyAdditionalFieldsAddDTO.setDescription("workDate");
                }
                companyAdditionalFieldsService.save(companyAdditionalFieldsAddDTO.to(CompanyAdditionalFieldsDO.class), tokenUser.getSiteId(), tokenUser.getUserId());
            }
        }

        returnAttendPunchRecord = returnAttendPunchRecord.stream().sorted(
                Comparator.comparing(AttendPunchRecordVO::getTimeDay)).collect(Collectors.toList());

        Page<AttendPunchRecordVO> page = PageKit.startPage(returnAttendPunchRecord,
                attendPunchRecordQuery.getPageNo(), attendPunchRecordQuery.getPageSize());
        return page.to(AttendPunchRecordVO.class);
    }

    private AttendPunchRecordVO buildReturnAttendPunchRecordVO(List<AttendPunchRecordVO> attendPunchRecordList) {
        // 根据打卡类型分组
        Map<Integer, List<AttendPunchRecordVO>> attendPunchRecordByPunchTypeMap = attendPunchRecordList
                .stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getPunchType));
        // 上班缺卡记录
        List<AttendPunchRecordVO> attendPunchRecordUpLack = attendPunchRecordByPunchTypeMap
                .get(PunchType.COMPLETE.getValue());
        // 下班缺卡记录
        List<AttendPunchRecordVO> attendPunchRecordDownLack = attendPunchRecordByPunchTypeMap
                .get(PunchType.INVALID_PUNCH.getValue());
        // 去掉重复生成的缺卡记录
        if (CollectionKit.isNotEmpty(attendPunchRecordUpLack)) {
            attendPunchRecordUpLack = attendPunchRecordUpLack.stream().collect(
                    Collectors.collectingAndThen(Collectors.toCollection(() ->
                            new TreeSet<>(Comparator.comparing(AttendPunchRecordVO::getStandardTime))), ArrayList::new));
        }
        if (CollectionKit.isNotEmpty(attendPunchRecordDownLack)) {
            attendPunchRecordDownLack = attendPunchRecordDownLack.stream().collect(
                    Collectors.collectingAndThen(Collectors.toCollection(() ->
                            new TreeSet<>(Comparator.comparing(AttendPunchRecordVO::getStandardTime))), ArrayList::new));
        }
        // 上班打卡记录
        List<AttendPunchRecordVO> attendPunchRecordUp = attendPunchRecordByPunchTypeMap
                .get(PunchType.ON_WORK.getValue());
        // 下班打卡记录
        List<AttendPunchRecordVO> attendPunchRecordDown = attendPunchRecordByPunchTypeMap
                .get(PunchType.OFF_WORK.getValue());
        // 根据创建时间排序
        if (CollectionKit.isNotEmpty(attendPunchRecordUp)) {
            attendPunchRecordUp = attendPunchRecordUp.stream().sorted(
                    Comparator.comparing(AttendPunchRecordVO::getGmtCreate)).collect(Collectors.toList());
        }
        if (CollectionKit.isNotEmpty(attendPunchRecordDown)) {
            attendPunchRecordDown = attendPunchRecordDown.stream().sorted(
                    Comparator.comparing(AttendPunchRecordVO::getGmtCreate)).collect(Collectors.toList());
        }

        AttendPunchRecordVO attendPunchRecordVO = attendPunchRecordList.get(0);
        attendPunchRecordVO.setTimeDay(attendPunchRecordVO.getYear() + "-"
                + attendPunchRecordVO.getMonth() + "-" + attendPunchRecordVO.getDay());
        // 工作时长
        int workTime = 0;
        // 缺卡次数
        int lackCount = CollectionUtils.isEmpty(attendPunchRecordUpLack) ?
                0 : attendPunchRecordUpLack.size();
        lackCount += CollectionUtils.isEmpty(attendPunchRecordDownLack) ?
                0 : attendPunchRecordDownLack.size();
        // 缺卡次数为 0 时
        if (lackCount == 0) {
            // 第二次上班打卡时间
            Date upTwo = null;
            // 上班记录
            if (CollectionKit.isNotEmpty(attendPunchRecordUp)) {
                AttendPunchRecordVO attendPunchRecordOne = attendPunchRecordUp.get(0);
                AttendPunchRecordArriveListVO arriveOne = new AttendPunchRecordArriveListVO();
                arriveOne.setArriveStatus(PunchStatus.find(attendPunchRecordOne.getPunchStatus()).getDesc());
                arriveOne.setArrivePlace(attendPunchRecordOne.getLocation());
                arriveOne.setArriveTime(DateKit8.format2DateTime(attendPunchRecordOne.getPunchTime()));
                arriveOne.setRangeState(attendPunchRecordOne.getRangeState() + "");
                attendPunchRecordVO.setArriveOne(arriveOne);
                if (attendPunchRecordUp.size() > 1) {
                    AttendPunchRecordVO attendPunchRecordTwo = attendPunchRecordUp.get(1);
                    upTwo = attendPunchRecordTwo.getPunchTime();
                    AttendPunchRecordArriveListVO arriveTwo = new AttendPunchRecordArriveListVO();
                    arriveTwo.setArriveStatus(PunchStatus.find(attendPunchRecordTwo.getPunchStatus()).getDesc());
                    arriveTwo.setArrivePlace(attendPunchRecordTwo.getLocation());
                    arriveTwo.setArriveTime(DateKit8.format2DateTime(attendPunchRecordTwo.getPunchTime()));
                    arriveTwo.setRangeState(attendPunchRecordTwo.getRangeState() + "");
                    attendPunchRecordVO.setArriveTwo(arriveTwo);
                }
            }
            // 下班记录
            if (CollectionKit.isNotEmpty(attendPunchRecordDown)) {
                if (upTwo == null) {
                    AttendPunchRecordVO attendPunchRecordOne = attendPunchRecordDown.get(attendPunchRecordDown.size() - 1);
                    AttendPunchRecordLeaveListVO leaveOne = new AttendPunchRecordLeaveListVO();
                    leaveOne.setLeaveStatus(PunchStatus.find(attendPunchRecordOne.getPunchStatus()).getDesc());
                    leaveOne.setLeavePlace(attendPunchRecordOne.getLocation());
                    leaveOne.setLeaveTime(DateKit8.format2DateTime(attendPunchRecordOne.getPunchTime()));
                    leaveOne.setRangeState(attendPunchRecordOne.getRangeState() + "");
                    attendPunchRecordVO.setLeaveOne(leaveOne);
                    workTime = attendPunchRecordOne.getWorkTime() == null ?
                            0 : attendPunchRecordOne.getWorkTime();
                } else {
                    AttendPunchRecordVO attendPunchRecordOne = attendPunchRecordDown.get(0);
                    AttendPunchRecordLeaveListVO leaveOne = new AttendPunchRecordLeaveListVO();
                    leaveOne.setLeaveStatus(PunchStatus.find(attendPunchRecordOne.getPunchStatus()).getDesc());
                    leaveOne.setLeavePlace(attendPunchRecordOne.getLocation());
                    leaveOne.setLeaveTime(DateKit8.format2DateTime(attendPunchRecordOne.getPunchTime()));
                    leaveOne.setRangeState(attendPunchRecordOne.getRangeState() + "");
                    attendPunchRecordVO.setLeaveOne(leaveOne);
                    if (attendPunchRecordDown.size() > 1) {
                        AttendPunchRecordLeaveListVO leaveTwo = new AttendPunchRecordLeaveListVO();
                        AttendPunchRecordVO attendPunchRecordTwo = attendPunchRecordDown.get(attendPunchRecordDown.size() - 1);
                        leaveTwo.setLeaveStatus(PunchStatus.find(attendPunchRecordTwo.getPunchStatus()).getDesc());
                        leaveTwo.setLeavePlace(attendPunchRecordTwo.getLocation());
                        leaveTwo.setLeaveTime(DateKit8.format2DateTime(attendPunchRecordTwo.getPunchTime()));
                        leaveTwo.setRangeState(attendPunchRecordTwo.getRangeState() + "");
                        attendPunchRecordVO.setLeaveTwo(leaveTwo);
                        // 根据时间判断  2021年8月21日之后的数据 工作时长求和
                        Date limitDate = DateKit8.parseDate("2021-08-21 00:00:00");
                        workTime = attendPunchRecordTwo.getWorkTime() == null ?
                                0 : attendPunchRecordTwo.getWorkTime();
                        if (attendPunchRecordTwo.getPunchTime().getTime() > limitDate.getTime()) {
                            // 新数据 求和
                            workTime += attendPunchRecordOne.getWorkTime() == null ?
                                    0 : attendPunchRecordOne.getWorkTime();
                        }
                    }
                }

            }
        }
        // 缺卡次数为 1 时 缺的肯定是下班卡
        if (lackCount == 1) {
            if (CollectionKit.isNotEmpty(attendPunchRecordUp)) {
                AttendPunchRecordVO attendPunchRecordOne = attendPunchRecordUp.get(0);
                AttendPunchRecordArriveListVO arriveOne = new AttendPunchRecordArriveListVO();
                arriveOne.setArriveStatus(PunchStatus.find(attendPunchRecordOne.getPunchStatus()).getDesc());
                arriveOne.setArrivePlace(attendPunchRecordOne.getLocation());
                arriveOne.setArriveTime(DateKit8.format2DateTime(attendPunchRecordOne.getPunchTime()));
                arriveOne.setRangeState(attendPunchRecordOne.getRangeState() + "");
                attendPunchRecordVO.setArriveOne(arriveOne);
                if (attendPunchRecordUp.size() > 1 && CollectionKit.isNotEmpty(attendPunchRecordDown)) {
                    AttendPunchRecordVO attendPunchRecordTwo = attendPunchRecordUp.get(1);
                    AttendPunchRecordArriveListVO arriveTwo = new AttendPunchRecordArriveListVO();
                    arriveTwo.setArriveStatus(PunchStatus.find(attendPunchRecordTwo.getPunchStatus()).getDesc());
                    arriveTwo.setArrivePlace(attendPunchRecordTwo.getLocation());
                    arriveTwo.setArriveTime(DateKit8.format2DateTime(attendPunchRecordTwo.getPunchTime()));
                    arriveTwo.setRangeState(attendPunchRecordTwo.getRangeState() + "");
                    attendPunchRecordVO.setArriveTwo(arriveTwo);
                    attendPunchRecordOne = attendPunchRecordDown.get(attendPunchRecordDown.size() - 1);
                    AttendPunchRecordLeaveListVO leaveOne = new AttendPunchRecordLeaveListVO();
                    leaveOne.setLeaveStatus(PunchStatus.find(attendPunchRecordOne.getPunchStatus()).getDesc());
                    leaveOne.setLeavePlace(attendPunchRecordOne.getLocation());
                    leaveOne.setLeaveTime(DateKit8.format2DateTime(attendPunchRecordOne.getPunchTime()));
                    leaveOne.setRangeState(attendPunchRecordOne.getRangeState() + "");
                    attendPunchRecordVO.setLeaveOne(leaveOne);
                    workTime = attendPunchRecordOne.getWorkTime() == null ?
                            0 : attendPunchRecordOne.getWorkTime();
                    AttendPunchRecordLeaveListVO leaveTwo = new AttendPunchRecordLeaveListVO();
                    leaveTwo.setLeaveStatus("下班缺卡");
                    attendPunchRecordVO.setLeaveTwo(leaveTwo);
                } else {
                    AttendPunchRecordLeaveListVO leaveOne = new AttendPunchRecordLeaveListVO();
                    leaveOne.setLeaveStatus("下班缺卡");
                    attendPunchRecordVO.setLeaveOne(leaveOne);
                }
            }
        }
        // 缺卡次数为 2 时 缺的是上班下班卡
        if (lackCount == 2) {
            if (CollectionKit.isNotEmpty(attendPunchRecordUp)) {
                AttendPunchRecordVO attendPunchRecordOne = attendPunchRecordUp.get(0);
                AttendPunchRecordArriveListVO arriveOne = new AttendPunchRecordArriveListVO();
                arriveOne.setArriveStatus(PunchStatus.find(attendPunchRecordOne.getPunchStatus()).getDesc());
                arriveOne.setArrivePlace(attendPunchRecordOne.getLocation());
                arriveOne.setArriveTime(DateKit8.format2DateTime(attendPunchRecordOne.getPunchTime()));
                arriveOne.setRangeState(attendPunchRecordOne.getRangeState() + "");
                attendPunchRecordVO.setArriveOne(arriveOne);
                AttendPunchRecordArriveListVO arriveTwo = new AttendPunchRecordArriveListVO();
                arriveTwo.setArriveStatus("上班缺卡");
                attendPunchRecordVO.setArriveTwo(arriveTwo);
                AttendPunchRecordLeaveListVO leaveOne = new AttendPunchRecordLeaveListVO();
                leaveOne.setLeaveStatus(PunchStatus.find(attendPunchRecordOne.getPunchStatus()).getDesc());
                leaveOne.setLeavePlace(attendPunchRecordOne.getLocation());
                leaveOne.setLeaveTime(DateKit8.format2DateTime(attendPunchRecordOne.getPunchTime()));
                leaveOne.setRangeState(attendPunchRecordOne.getRangeState() + "");
                attendPunchRecordVO.setLeaveOne(leaveOne);
                workTime = attendPunchRecordOne.getWorkTime() == null ?
                        0 : attendPunchRecordOne.getWorkTime();
                AttendPunchRecordLeaveListVO leaveTwo = new AttendPunchRecordLeaveListVO();
                leaveTwo.setLeaveStatus("下班缺卡");
                attendPunchRecordVO.setLeaveTwo(leaveTwo);
            } else {
                AttendPunchRecordArriveListVO arriveOne = new AttendPunchRecordArriveListVO();
                arriveOne.setArriveStatus("上班缺卡");
                attendPunchRecordVO.setArriveOne(arriveOne);
                AttendPunchRecordLeaveListVO leaveOne = new AttendPunchRecordLeaveListVO();
                leaveOne.setLeaveStatus("下班缺卡");
                attendPunchRecordVO.setLeaveOne(leaveOne);
            }
        }
        // 缺卡次数为 3 时 只有一次上班卡
        if (lackCount == 3) {
            if (CollectionKit.isNotEmpty(attendPunchRecordUp)) {
                AttendPunchRecordVO attendPunchRecordOne = attendPunchRecordUp.get(0);
                AttendPunchRecordArriveListVO arriveOne = new AttendPunchRecordArriveListVO();
                arriveOne.setArriveStatus(PunchStatus.find(attendPunchRecordOne.getPunchStatus()).getDesc());
                arriveOne.setArrivePlace(attendPunchRecordOne.getLocation());
                arriveOne.setArriveTime(DateKit8.format2DateTime(attendPunchRecordOne.getPunchTime()));
                arriveOne.setRangeState(attendPunchRecordOne.getRangeState() + "");
                attendPunchRecordVO.setArriveOne(arriveOne);
                AttendPunchRecordArriveListVO arriveTwo = new AttendPunchRecordArriveListVO();
                arriveTwo.setArriveStatus("上班缺卡");
                attendPunchRecordVO.setArriveTwo(arriveTwo);
                AttendPunchRecordLeaveListVO leaveOne = new AttendPunchRecordLeaveListVO();
                leaveOne.setLeaveStatus("下班缺卡");
                attendPunchRecordVO.setLeaveOne(leaveOne);
                AttendPunchRecordLeaveListVO leaveTwo = new AttendPunchRecordLeaveListVO();
                leaveTwo.setLeaveStatus("下班缺卡");
                attendPunchRecordVO.setLeaveTwo(leaveTwo);
            }
        }
        // 缺卡次数为 4 时 全部缺卡
        if (lackCount >= 4) {
            AttendPunchRecordArriveListVO arriveOne = new AttendPunchRecordArriveListVO();
            arriveOne.setArriveStatus("上班缺卡");
            attendPunchRecordVO.setArriveOne(arriveOne);
            AttendPunchRecordArriveListVO arriveTwo = new AttendPunchRecordArriveListVO();
            arriveTwo.setArriveStatus("上班缺卡");
            attendPunchRecordVO.setArriveTwo(arriveTwo);
            AttendPunchRecordLeaveListVO leaveOne = new AttendPunchRecordLeaveListVO();
            leaveOne.setLeaveStatus("下班缺卡");
            attendPunchRecordVO.setLeaveOne(leaveOne);
            AttendPunchRecordLeaveListVO leaveTwo = new AttendPunchRecordLeaveListVO();
            leaveTwo.setLeaveStatus("下班缺卡");
            attendPunchRecordVO.setLeaveTwo(leaveTwo);
        }
        attendPunchRecordVO.setWorkTime(workTime);
        attendPunchRecordVO.setWorkDate(workTime / 60 + "小时" + workTime % 60 + "分钟");
        return attendPunchRecordVO;
    }

    /**
     * 对某个人某一天的打卡记录进行合并处理，找出对应上下班必要信息供前端展示
     *
     * @param orderByArrive 上班的分组
     * @param orderByLeave  下班的分组
     * @param calibration   是否校准
     * @return 返回内容
     */
    private AttendPunchRecordVO arriveAndLeave(String orderByArrive, String orderByLeave, String calibration) {
        AttendPunchRecordVO attendPunchRecordVO = new AttendPunchRecordVO();
        // 上班集合
        List<AttendPunchRecordArriveListVO> arriveList = new ArrayList<>();
        // 下班集合
        List<AttendPunchRecordLeaveListVO> leaveList = new ArrayList<>();
        if (!StringUtils.isEmpty(orderByArrive)) {
            String[] arriveGroup = orderByArrive.split(",");
            for (String arriveStr : arriveGroup) {
                String[] arriveItems = arriveStr.split("//");
                if (!"2".equals(arriveItems[0])) {
                    AttendPunchRecordArriveListVO arriveListVO = new AttendPunchRecordArriveListVO();
                    switch (arriveItems[0]) {
                        //上班打卡
                        case "1":
                            if (arriveItems.length >= 3) {
                                arriveListVO.setArriveStatus(arriveItems[2]);
                            }
                            if (arriveItems.length >= 2) {
                                arriveListVO.setArriveTime("=".equals(arriveItems[1]) ? null : arriveItems[1]);
                            }
                            if (arriveItems.length >= 4) {
                                arriveListVO.setArrivePlace(arriveItems[3]);
                            }
                            if (arriveItems.length >= 5) {
                                arriveListVO.setRangeState(arriveItems[4]);
                            }
                            break;
                        case "3":
                            if (arriveItems.length >= 3) {
                                arriveListVO.setArriveStatus("8");
                            }
                            break;
                        default:
                            break;
                    }
                    String arriveStatus;
                    if (StringUtils.isEmpty(arriveListVO.getArriveStatus())) {
                        arriveStatus = "8";
                    } else {
                        arriveStatus = arriveListVO.getArriveStatus();
                    }
                    arriveListVO.setArriveStatus(this.statusName(arriveStatus));
                    arriveList.add(arriveListVO);
                }
            }
        }
        if (!StringUtils.isEmpty(orderByLeave)) {
            String[] leaveGroup = orderByLeave.split(",");
            int index = checkLeaveGroup(leaveGroup);
            if (index == -3) {
                AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO = new AttendPunchRecordLeaveListVO();
                attendPunchRecordLeaveListVO.setLeaveStatus("下班缺卡");
                leaveList.add(attendPunchRecordLeaveListVO);
                if (leaveGroup != null && leaveGroup.length > 1) {
                    String[] split = leaveGroup[1].split("//");
                    AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO2 = new AttendPunchRecordLeaveListVO();
                    fillLeaveListVO(split, attendPunchRecordLeaveListVO2, leaveList);
                }
            } else {
                for (int i = 0; i < leaveGroup.length; i++) {
                    if (i != 0 && i != index) {
                        continue;
                    }
                    String[] split = leaveGroup[i].split("//");
                    AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO = new AttendPunchRecordLeaveListVO();
                    fillLeaveListVO(split, attendPunchRecordLeaveListVO, leaveList);
                    if (i == index) {
                        break;
                    }
                }
            }
        }
        if (!StringUtils.isEmpty(calibration)) {
            String[] split = calibration.split(",");
            String[] one = split[0].split("//");
            switch (one[0]) {
                //上班打卡
                case "1":
                    attendPunchRecordVO.setIsCalibrationArrive("1".equals(one[1]));
                    if (split.length > 1) {
                        String[] last = split[split.length - 1].split("//");
                        attendPunchRecordVO.setIsCalibrationLeave("1".equals(last[1]));
                    } else {
                        attendPunchRecordVO.setIsCalibrationLeave(false);
                    }
                    break;
                //下班打卡
                case "2":
                    attendPunchRecordVO.setIsCalibrationArrive(false);
                    attendPunchRecordVO.setIsCalibrationLeave(one[1].equals("1"));
                    break;
                default:
                    break;
            }
        }
        attendPunchRecordVO.setArriveList(arriveList);
        attendPunchRecordVO.setLeaveList(leaveList);
        return attendPunchRecordVO;
    }

    /**
     * 对某个人某一天的打卡记录进行合并处理，找出对应上下班必要信息供前端展示(上下班打卡集合不重)
     *
     * @param orderByArrive 上班的分组
     * @param orderByLeave  下班的分组
     * @param calibration   是否校准
     * @return 返回内容
     */
    private AttendPunchRecordVO arriveAndLeave2(String orderByArrive, String orderByLeave, String calibration) {
        AttendPunchRecordVO attendPunchRecordVO = new AttendPunchRecordVO();
        // 上班集合
        List<AttendPunchRecordArriveListVO> arriveList = new ArrayList<>();
        // 下班集合
        List<AttendPunchRecordLeaveListVO> leaveList = new ArrayList<>();
        if (!StringUtils.isEmpty(orderByArrive)) {
            List<String> arriveGroup = ArrayKit.split(orderByArrive, ",");
            // 删除里面是下班的信息
            arriveGroup.removeIf(str -> {
                String[] arriveItems = str.split("//");
                if (arriveItems[0] == null || "2".equals(arriveItems[0]) || "4".equals(arriveItems[0])) {
                    return true;
                }
                return false;
            });
            for (String arriveStr : arriveGroup) {
                Boolean arrive = false;
                String[] arriveItems = arriveStr.split("//");
                if (!"2".equals(arriveItems[0])) {
                    AttendPunchRecordArriveListVO arriveListVO = new AttendPunchRecordArriveListVO();
                    switch (arriveItems[0]) {
                        //上班打卡
                        case "1":
                            if (arriveItems.length >= 3) {
                                arriveListVO.setArriveStatus(arriveItems[2]);
                            }
                            if (arriveItems.length >= 2) {
                                arriveListVO.setArriveTime("=".equals(arriveItems[1]) ? null : arriveItems[1]);
                            }
                            if (arriveItems.length >= 4) {
                                arriveListVO.setArrivePlace(arriveItems[3]);
                            }
                            if (arriveItems.length >= 5) {
                                arriveListVO.setRangeState(arriveItems[4]);
                            }
                            break;
                        case "3":
                            if (arriveItems.length >= 3) {
                                arriveListVO.setArriveStatus("8");
                            }
                            break;
                        default:
                            // 其他情况不统计
                            arrive = true;
                            break;
                    }
                    if (arrive) {
                        continue;
                    }
                    String arriveStatus;
                    if (StringUtils.isEmpty(arriveListVO.getArriveStatus())) {
                        arriveStatus = "8";
                    } else {
                        arriveStatus = arriveListVO.getArriveStatus();
                    }
                    arriveListVO.setArriveStatus(this.statusName(arriveStatus));
                    arriveList.add(arriveListVO);
                }
            }
        }
        if (!StringUtils.isEmpty(orderByLeave)) {
            List<String> leaveGroup = ArrayKit.split(orderByLeave, ",");
            // 删除里面是上班的信息
            leaveGroup.removeIf(str -> {
                String[] arriveItems = str.split("//");
                if (arriveItems[0] == null || "1".equals(arriveItems[0]) || "3".equals(arriveItems[0])) {
                    return true;
                }
                return false;
            });
            if (leaveGroup == null) {
                leaveGroup = new ArrayList<>();
            }
            int index = checkLeaveGroup2(leaveGroup);
            if (index == -3) {
                AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO = new AttendPunchRecordLeaveListVO();
                attendPunchRecordLeaveListVO.setLeaveStatus("下班缺卡");
                leaveList.add(attendPunchRecordLeaveListVO);
                if (leaveGroup != null && leaveGroup.size() > 1) {
                    String[] split = leaveGroup.get(1).split("//");
                    AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO2 = new AttendPunchRecordLeaveListVO();
                    fillLeaveListVO(split, attendPunchRecordLeaveListVO2, leaveList);
                }
            } else {
                for (int i = 0; i < leaveGroup.size(); i++) {
                    String[] split = leaveGroup.get(i).split("//");
                    AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO = new AttendPunchRecordLeaveListVO();
                    fillLeaveListVO(split, attendPunchRecordLeaveListVO, leaveList);
                }
            }
        }
        if (!StringUtils.isEmpty(calibration)) {
            String[] split = calibration.split(",");
            String[] one = split[0].split("//");
            switch (one[0]) {
                //上班打卡
                case "1":
                    attendPunchRecordVO.setIsCalibrationArrive("1".equals(one[1]));
                    if (split.length > 1) {
                        String[] last = split[split.length - 1].split("//");
                        attendPunchRecordVO.setIsCalibrationLeave("1".equals(last[1]));
                    } else {
                        attendPunchRecordVO.setIsCalibrationLeave(false);
                    }
                    break;
                //下班打卡
                case "2":
                    attendPunchRecordVO.setIsCalibrationArrive(false);
                    attendPunchRecordVO.setIsCalibrationLeave(one[1].equals("1"));
                    break;
                default:
                    break;
            }
        }
        attendPunchRecordVO.setArriveList(arriveList);
        attendPunchRecordVO.setLeaveList(leaveList);
        return attendPunchRecordVO;
    }

    private int checkLeaveGroup(String[] leaveGroup) {
        String[] leaveItems1 = leaveGroup[0].split("//");
        // 第一个是上班卡
        if ("1".equals(leaveItems1[0])) {
            return -2;
        } else if ("4".equals(leaveItems1[0])) {
            // 第一个是下班缺卡
            return -3;
        } else {
            // 第一个是下班卡
            for (int i = 0; i < leaveGroup.length; i++) {
                String[] leaveItems = leaveGroup[i].split("//");
                if ("1".equals(leaveItems[0])) {
                    return i - 1;
                }
            }
        }
        return -4;
    }

    private int checkLeaveGroup2(List<String> leaveGroup) {
        if (leaveGroup == null || leaveGroup.size() == 0) {
            return 0;
        }
        String[] leaveItems1 = leaveGroup.get(0).split("//");
        // 第一个是上班卡
        if ("1".equals(leaveItems1[0])) {
            return -2;
        } else if ("4".equals(leaveItems1[0])) {
            // 第一个是下班缺卡
            return -3;
        } else {
            // 第一个是下班卡
            for (int i = 0; i < leaveGroup.size(); i++) {
                String[] leaveItems = leaveGroup.get(i).split("//");
                if ("1".equals(leaveItems[0])) {
                    return i - 1;
                }
            }
        }
        return -4;
    }

    private void fillLeaveListVO(String[] split, AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO,
                                 List<AttendPunchRecordLeaveListVO> leaveList) {
        switch (split[0]) {
            //下班打卡
            case "2":
                if (split.length >= 3) {
                    attendPunchRecordLeaveListVO.setLeaveStatus(split[2]);
                }
                if (split.length >= 2) {
                    attendPunchRecordLeaveListVO.setLeaveTime("=".equals(split[1]) ? null : split[1]);
                }
                if (split.length >= 4) {
                    attendPunchRecordLeaveListVO.setLeavePlace(split[3]);
                }
                if (split.length >= 5) {
                    attendPunchRecordLeaveListVO.setRangeState(split[4]);
                }
                break;
            case "4":
                if (split.length >= 3) {
                    attendPunchRecordLeaveListVO.setLeaveStatus("9");
                }
                break;
            default:
                break;
        }
        String leaveStatus;
        if (StringUtils.isEmpty(attendPunchRecordLeaveListVO.getLeaveStatus())) {
            leaveStatus = "";
        } else {
            leaveStatus = this.statusName(attendPunchRecordLeaveListVO.getLeaveStatus());
        }
        attendPunchRecordLeaveListVO.setLeaveStatus(leaveStatus);
        leaveList.add(attendPunchRecordLeaveListVO);
    }

    private String statusName(String statusCode) {
        if (StringUtils.isEmpty(statusCode)) {
            return null;
        }
        String status;
        //0：无效打卡，1：正常，2：迟到，3：早退
        //用于上下班缺卡的code：8：上班缺卡，9：下班缺卡
        switch (statusCode) {
            case "0":
                status = "无效打卡";
                break;
            case "1":
                status = "正常";
                break;
            case "2":
                status = "迟到";
                break;
            case "3":
                status = "早退";
                break;
            case "8":
                status = "上班缺卡";
                break;
            case "9":
                status = "下班缺卡";
                break;
            default:
                status = null;
                break;
        }
        return status;
    }

    @Override
    public List<AttendPunchRecordVO> selectAttendByDayAndEmpId(AttendPunchRecordQuery attendPunchRecordQuery, TokenUser tokenUser) {
        List<AttendPunchRecordVO> attendArriveList = new ArrayList<>();
        List<AttendPunchRecordVO> attendLeaveList = new ArrayList<>();
        List<AttendPunchRecordVO> lackArriveList = new ArrayList<>();
        List<AttendPunchRecordVO> lackLeaveList = new ArrayList<>();
        attendPunchRecordDAO.selectAttendByDayAndEmpId(attendPunchRecordQuery, tokenUser.getSiteId())
                .forEach(attendPunchRecordVO -> {
                    switch (attendPunchRecordVO.getPunchType()) {
                        case 1:
                            attendArriveList.add(attendPunchRecordVO);
                            break;
                        case 2:
                            attendLeaveList.add(attendPunchRecordVO);
                            break;
                        case 3:
                            lackArriveList.add(attendPunchRecordVO);
                            break;
                        case 4:
                            lackLeaveList.add(attendPunchRecordVO);
                            break;
                        default:
                            break;
                    }
                });
        // 判断该规则的打卡次数是否为4次
        String attendPlanId = "";
        if (!CollectionUtils.isEmpty(attendArriveList)) {
            attendPlanId = attendArriveList.get(attendArriveList.size() - 1).getAttendPlanId();
        }
        if (!CollectionUtils.isEmpty(attendLeaveList) && StrKit.isEmpty(attendPlanId)) {
            attendPlanId = attendLeaveList.get(attendLeaveList.size() - 1).getAttendPlanId();
        }
        if (!CollectionUtils.isEmpty(lackArriveList) && StrKit.isEmpty(attendPlanId)) {
            attendPlanId = lackArriveList.get(lackArriveList.size() - 1).getAttendPlanId();
        }
        if (!CollectionUtils.isEmpty(lackLeaveList) && StrKit.isEmpty(attendPlanId)) {
            attendPlanId = lackLeaveList.get(lackLeaveList.size() - 1).getAttendPlanId();
        }
        if (StrKit.isEmpty(attendPlanId)) {
            return new ArrayList<>();
        }
        // 查询考勤打卡时间
        AttendPunchTimeQuery attendPunchTimeQuery = new AttendPunchTimeQuery();
        attendPunchTimeQuery.setAttendPlanId(attendPlanId);
        List<AttendPunchTimeDO> attendPunchTimeList = attendPunchTimeService.selectDO(attendPunchTimeQuery, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(attendPunchTimeList)) {
//            throw new ParamException("未设置考勤打卡时间");
            return new ArrayList<>();
        }
        List<AttendPeriodDTO> attendPeriodDTOList = JSON.parseArray(attendPunchTimeList.get(0).getPeriodJson(), AttendPeriodDTO.class);
        if (CollectionUtils.isEmpty(attendPeriodDTOList)) {
//            throw new HrException("未设置考勤打卡时间");
            return new ArrayList<>();
        }
        List<AttendPunchRecordVO> attendPunchRecordList = new ArrayList<>();
        if (attendPeriodDTOList.size() >= 2) {
            // 第一次上班打卡信息
            if (!CollectionUtils.isEmpty(attendArriveList)) {
                attendPunchRecordList.add(attendArriveList.get(0));
            } else if (!CollectionUtils.isEmpty(lackArriveList)) {
                attendPunchRecordList.add(lackArriveList.get(0));
            }
            // 第一次下班打卡信息
            if (!CollectionUtils.isEmpty(attendLeaveList)) {
                AttendPunchRecordVO attendPunchRecordVO = new AttendPunchRecordVO();
                if (attendArriveList.size() >= 2) {
                    // 找到第一次上班到第二次上班的时间段中最后的一次下班打卡记录
                    for (int i = 0; i < attendLeaveList.size(); i++) {
                        if (attendLeaveList.get(i).getPunchTime().getTime() <
                                attendArriveList.get(1).getPunchTime().getTime()) {
                            attendPunchRecordVO = attendLeaveList.get(i);
                        }
                    }
                    attendPunchRecordList.add(attendPunchRecordVO);
                } else {
                    // 上班打卡就一次记录  所以下班使用下班记录的最后一条
                    attendPunchRecordList.add(attendLeaveList.get(attendLeaveList.size() - 1));
                }
            } else if (!CollectionUtils.isEmpty(lackLeaveList)) {
                attendPunchRecordList.add(lackLeaveList.get(0));
            }
            // 第二次上班打卡信息
            if (attendArriveList.size() >= 2) {
                attendPunchRecordList.add(attendArriveList.get(attendArriveList.size() - 1));
            } else if (!CollectionUtils.isEmpty(lackArriveList)) {
                attendPunchRecordList.add(lackArriveList.get(lackArriveList.size() - 1));
            }
            // 第二次下班打卡信息
            if (attendArriveList.size() >= 2 && attendLeaveList.size() >= 2) {
                attendPunchRecordList.add(attendLeaveList.get(attendLeaveList.size() - 1));
            } else if (!CollectionUtils.isEmpty(lackLeaveList)) {
                attendPunchRecordList.add(lackLeaveList.get(lackLeaveList.size() - 1));
            }
        } else {
            if (!CollectionUtils.isEmpty(attendArriveList)) {
                attendPunchRecordList.add(attendArriveList.get(attendArriveList.size() - 1));
            } else if (!CollectionUtils.isEmpty(lackArriveList)) {
                attendPunchRecordList.add(lackArriveList.get(lackArriveList.size() - 1));
            }
            if (!CollectionUtils.isEmpty(attendLeaveList)) {
                attendPunchRecordList.add(attendLeaveList.get(attendLeaveList.size() - 1));
            } else if (!CollectionUtils.isEmpty(lackLeaveList)) {
                attendPunchRecordList.add(lackLeaveList.get(lackLeaveList.size() - 1));
            }
        }
        return attendPunchRecordList.stream().peek(attendPunchRecordVO -> {
            if (attendPunchRecordVO.getIsCalibration() != null && attendPunchRecordVO.getIsCalibration()) {
                AttendPunchCalibrationQuery attendPunchCalibrationQuery = new AttendPunchCalibrationQuery();
                attendPunchCalibrationQuery.setPunchRecordId(attendPunchRecordVO.getId());
                List<AttendPunchCalibrationDO> attendPunchCalibration =
                        attendPunchCalibrationService.selectDO(attendPunchCalibrationQuery, tokenUser.getSiteId());
                if (!CollectionUtils.isEmpty(attendPunchCalibration)) {
                    attendPunchRecordVO.setRemark(attendPunchCalibration.get(0).getRemark());
                    UserDO userDO = userProviderService.selectUserById(attendPunchCalibration.get(0).getCalibrationMethod());
                    attendPunchRecordVO.setCalibrationNameHistory(userDO != null ? userDO.getName() : null);
                }
            }
        }).collect(Collectors.toList());
    }

    /**
     * 根据查询参数，构建example
     *
     * @param attendPunchRecordQuery 查询参数
     * @param siteId                 所属站点id
     * @return example
     */
    private Example buildExample(AttendPunchRecordQuery attendPunchRecordQuery, String siteId) {
        Example example = new Example(AttendPunchRecordDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (attendPunchRecordQuery.getStandardTimeLst() != null) {
            example.and().andIn("standardTime", attendPunchRecordQuery.getStandardTimeLst());
        }
        if (attendPunchRecordQuery.getNotEqPunchStatus() != null) {
            example.and().andNotEqualTo("punchStatus", attendPunchRecordQuery.getNotEqPunchStatus());
        }
        if (attendPunchRecordQuery.getCompanyId() != null) {
            example.and().andLike("companyId", "%" + attendPunchRecordQuery.getCompanyId() + "%");
        }
        if (attendPunchRecordQuery.getCompanyName() != null) {
            example.and().andLike("companyName", "%" + attendPunchRecordQuery.getCompanyName() + "%");
        }
        if (attendPunchRecordQuery.getDeptId() != null) {
            example.and().andLike("deptId", "%" + attendPunchRecordQuery.getDeptId() + "%");
        }
        if (attendPunchRecordQuery.getDeptName() != null) {
            example.and().andLike("deptName", "%" + attendPunchRecordQuery.getDeptName() + "%");
        }
        if (attendPunchRecordQuery.getEmpInfoId() != null) {
            example.and().andLike("empInfoId", "%" + attendPunchRecordQuery.getEmpInfoId() + "%");
        }
        if (attendPunchRecordQuery.getEmpInfoName() != null) {
            example.and().andLike("empInfoName", "%" + attendPunchRecordQuery.getEmpInfoName() + "%");
        }
        if (attendPunchRecordQuery.getAttendPlanId() != null) {
            example.and().andLike("attendPlanId", "%" + attendPunchRecordQuery.getAttendPlanId() + "%");
        }
        if (attendPunchRecordQuery.getAttendPlanName() != null) {
            example.and().andLike("attendPlanName", "%" + attendPunchRecordQuery.getAttendPlanName() + "%");
        }
        if (attendPunchRecordQuery.getYear() != null) {
            example.and().andEqualTo("year", attendPunchRecordQuery.getYear());
        }
        if (attendPunchRecordQuery.getMonth() != null) {
            example.and().andEqualTo("month", attendPunchRecordQuery.getMonth());
        }
        if (attendPunchRecordQuery.getDay() != null) {
            example.and().andEqualTo("day", attendPunchRecordQuery.getDay());
        }
        if (attendPunchRecordQuery.getPunchType() != null) {
            example.and().andEqualTo("punchType", attendPunchRecordQuery.getPunchType());
        }
        if (attendPunchRecordQuery.getPunchRange() != null) {
            example.and().andEqualTo("punchRange", attendPunchRecordQuery.getPunchRange());
        }
        if (attendPunchRecordQuery.getStandardTime() != null) {
            example.and().andEqualTo("standardTime", attendPunchRecordQuery.getStandardTime());
        }
        if (attendPunchRecordQuery.getPunchTime() != null) {
            example.and().andEqualTo("punchTime", attendPunchRecordQuery.getPunchTime());
        }
        if (attendPunchRecordQuery.getPunchStatus() != null) {
            example.and().andEqualTo("punchStatus", attendPunchRecordQuery.getPunchStatus());
        }
        if (attendPunchRecordQuery.getMinute() != null) {
            example.and().andEqualTo("minute", attendPunchRecordQuery.getMinute());
        }
        if (attendPunchRecordQuery.getWorkTime() != null) {
            example.and().andEqualTo("workTime", attendPunchRecordQuery.getWorkTime());
        }
        if (attendPunchRecordQuery.getDecisionDesc() != null) {
            example.and().andLike("decisionDesc", "%" + attendPunchRecordQuery.getDecisionDesc() + "%");
        }
        if (attendPunchRecordQuery.getCoordinate() != null) {
            example.and().andLike("coordinate", "%" + attendPunchRecordQuery.getCoordinate() + "%");
        }
        if (attendPunchRecordQuery.getLocation() != null) {
            example.and().andLike("location", "%" + attendPunchRecordQuery.getLocation() + "%");
        }
        if (attendPunchRecordQuery.getPunchWifi() != null) {
            example.and().andLike("punchWifi", "%" + attendPunchRecordQuery.getPunchWifi() + "%");
        }
        if (attendPunchRecordQuery.getPunchSource() != null) {
            example.and().andEqualTo("punchSource", attendPunchRecordQuery.getPunchSource());
        }
        if (attendPunchRecordQuery.getIsCalibration() != null) {
            example.and().andEqualTo("isCalibration", attendPunchRecordQuery.getIsCalibration());
        }
        if (attendPunchRecordQuery.getIsMakeUp() != null) {
            example.and().andEqualTo("isMakeUp", attendPunchRecordQuery.getIsMakeUp());
        }
        if (attendPunchRecordQuery.getHisStandardTime() != null) {
            example.and().andEqualTo("hisStandardTime", attendPunchRecordQuery.getHisStandardTime());
        }
        if (attendPunchRecordQuery.getHisPunchTime() != null) {
            example.and().andEqualTo("hisPunchTime", attendPunchRecordQuery.getHisPunchTime());
        }
        if (attendPunchRecordQuery.getHisPunchStatus() != null) {
            example.and().andEqualTo("hisPunchStatus", attendPunchRecordQuery.getHisPunchStatus());
        }
        if (attendPunchRecordQuery.getPunchSerial() != null) {
            example.and().andEqualTo("punchSerial", attendPunchRecordQuery.getPunchSerial());
        }
        if (attendPunchRecordQuery.getGmtCreateStart() != null &&
                attendPunchRecordQuery.getGmtCreateEnd() != null) {
            example.and().andBetween("gmtCreate", attendPunchRecordQuery.getGmtCreateStart(),
                    attendPunchRecordQuery.getGmtCreateEnd());
        }
        if (attendPunchRecordQuery.getCreateUserId() != null) {
            example.and().andLike("createUserId", "%" + attendPunchRecordQuery.getCreateUserId() + "%");
        }
        if (attendPunchRecordQuery.getGmtModifiedStart() != null &&
                attendPunchRecordQuery.getGmtModifiedEnd() != null) {
            example.and().andBetween("gmtModified", attendPunchRecordQuery.getGmtModifiedStart(),
                    attendPunchRecordQuery.getGmtModifiedEnd());
        }
        if (attendPunchRecordQuery.getModifiedUserId() != null) {
            example.and().andLike("modifiedUserId", "%" + attendPunchRecordQuery.getModifiedUserId() + "%");
        }
        // 排序
        ExampleKit.setExampleOrder(example, attendPunchRecordQuery.getOrders());
        return example;
    }

    @Override
    public List<AttendPunchRecordVO> exportAttendPunchRecord(TokenUser tokenUser, AttendPunchRecordQuery attendPunchRecordQuery) {
        return attendPunchRecordDAO.selectAttendPunchRecord(attendPunchRecordQuery, tokenUser.getSiteId())
                .stream().peek(attendPunchRecordVO -> {
                    if (attendPunchRecordVO.getNormalDay() != null && attendPunchRecordVO.getUnusualDay() != null) {
                        attendPunchRecordVO.setNormalDay(attendPunchRecordVO.getNormalDay() - attendPunchRecordVO.getUnusualDay());
                    }
                    if (attendPunchRecordVO.getBeLateTime() == null) {
                        attendPunchRecordVO.setBeLateTime(0);
                    }
                    if (attendPunchRecordVO.getLeaveEarlyTime() == null) {
                        attendPunchRecordVO.setLeaveEarlyTime(0);
                    }
                    if (!StringUtils.isEmpty(attendPunchRecordVO.getEmpInfoId())) {
                        List<AttendPunchRecordVO> attendPunchRecordVOS =
                                attendPunchRecordDAO.selectLeaveEarly(attendPunchRecordQuery,
                                        attendPunchRecordVO.getEmpInfoId(), tokenUser.getSiteId());
                        if (!CollectionUtils.isEmpty(attendPunchRecordVOS) && attendPunchRecordVOS.get(0) != null) {
                            Integer leaveEarlyCount = attendPunchRecordVOS.get(0).getLeaveEarlyCount() == null ?
                                    0 : attendPunchRecordVOS.get(0).getLeaveEarlyCount();
                            attendPunchRecordVO.setLeaveEarlyCount(leaveEarlyCount);
                            Integer leaveEarlyTime = attendPunchRecordVOS.get(0).getLeaveEarlyTime() == null ?
                                    0 : attendPunchRecordVOS.get(0).getLeaveEarlyTime();
                            attendPunchRecordVO.setLeaveEarlyTime(leaveEarlyTime);
                            attendPunchRecordVO.setUnusualCount(attendPunchRecordVO.getUnusualCount() + leaveEarlyCount);
                            attendPunchRecordVO.setWorkDate(this.workTime(attendPunchRecordVOS.get(0).getWorkTime()));
                        } else {
                            attendPunchRecordVO.setLeaveEarlyCount(0);
                            attendPunchRecordVO.setLeaveEarlyTime(0);
                            attendPunchRecordVO.setWorkDate(this.workTime(null));
                        }
                    }
                }).collect(Collectors.toList());
    }

    @Override
    public List<AttendPunchRecordVO> exportAttendMonth(AttendPunchRecordQuery attendPunchRecordQuery, TokenUser tokenUser) {
        return attendPunchRecordDAO.selectAttendMonth(attendPunchRecordQuery, tokenUser.getSiteId())
                .stream().peek(attendBean -> {
                    AttendPunchRecordVO attendPunchRecordVO =
                            this.arriveAndLeave2(attendBean.getOrderByArrive(),
                                    attendBean.getOrderByLeave(), attendBean.getCalibration());
                    if (attendPunchRecordVO != null) {
                        // 如果上班集合都有时间  则按照时间排序
                        if (attendPunchRecordVO.getArriveList() != null) {
                            List<AttendPunchRecordArriveListVO> attendPunchRecordArriveListVOS
                                    = attendPunchRecordVO.getArriveList();
                            AtomicBoolean sort = new AtomicBoolean(true);
                            attendPunchRecordArriveListVOS.forEach(attendPunchRecordArriveListVO -> {
                                if (StrKit.isEmpty(attendPunchRecordArriveListVO.getArriveTime())) {
                                    sort.set(false);
                                }
                            });
                            if (sort.get()) {
                                Collections.sort(attendPunchRecordArriveListVOS);
                            }
                        }
                        // 如果下班集合都有时间  则按照时间排序
                        if (attendPunchRecordVO.getLeaveList() != null) {
                            List<AttendPunchRecordLeaveListVO> attendPunchRecordLeaveListVOList
                                    = attendPunchRecordVO.getLeaveList();
                            AtomicBoolean sort = new AtomicBoolean(true);
                            attendPunchRecordLeaveListVOList.forEach(attendPunchRecordLeaveListVO -> {
                                if (StrKit.isEmpty(attendPunchRecordLeaveListVO.getLeaveTime())) {
                                    sort.set(false);
                                }
                            });
                            if (sort.get()) {
                                Collections.sort(attendPunchRecordLeaveListVOList);
                            } else {
                                Collections.reverse(attendPunchRecordVO.getLeaveList());
                            }
                        }
                        attendBean.setArriveList(attendPunchRecordVO.getArriveList());
                        attendBean.setLeaveList(attendPunchRecordVO.getLeaveList());
                        if (attendPunchRecordVO.getArriveList().size() > 1) {
                            AttendPunchRecordArriveListVO attendPunchRecordArriveOne = attendPunchRecordVO.getArriveList().get(0);
                            AttendPunchRecordArriveListVO attendPunchRecordArriveTwo = attendPunchRecordVO.getArriveList().get(1);
                            attendBean.setArriveStatus(attendPunchRecordArriveOne.getArriveStatus());
                            attendBean.setArriveTime(attendPunchRecordArriveOne.getArriveTime());
                            attendBean.setArrivePlace(attendPunchRecordArriveOne.getArrivePlace());
                            attendBean.setArriveStatusTwo(attendPunchRecordArriveTwo.getArriveStatus());
                            attendBean.setArriveTimeTwo(attendPunchRecordArriveTwo.getArriveTime());
                            attendBean.setArrivePlaceTwo(attendPunchRecordArriveTwo.getArrivePlace());
                        } else if (attendPunchRecordVO.getArriveList().size() == 1) {
                            AttendPunchRecordArriveListVO attendPunchRecordArriveOne = attendPunchRecordVO.getArriveList().get(0);
                            attendBean.setArriveStatus(attendPunchRecordArriveOne.getArriveStatus());
                            attendBean.setArriveTime(attendPunchRecordArriveOne.getArriveTime());
                            attendBean.setArrivePlace(attendPunchRecordArriveOne.getArrivePlace());
                        }
                        AttendPunchRecordLeaveListVO attendPunchRecordLeaveOne = new AttendPunchRecordLeaveListVO();
                        AttendPunchRecordLeaveListVO attendPunchRecordLeaveTwo = new AttendPunchRecordLeaveListVO();
                        if (attendPunchRecordVO.getLeaveList().size() > 1) {
                            if (attendPunchRecordVO.getArriveList().size() > 1) {
                                // 如果有两条上班卡记录
                                String arriveTime = attendPunchRecordVO.getArriveList().get(1).getArriveTime();
                                // 找到第一次上班到第二次上班的时间段中最后的一次下班打卡记录
                                AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO = attendPunchRecordVO.getLeaveList().get(0);
                                AttendPunchRecordLeaveListVO attendPunchRecordLeaveListLeave;
                                if ("下班缺卡".equals(attendPunchRecordVO.getLeaveList().get(1).getLeaveStatus())) {
                                    attendPunchRecordLeaveListLeave = attendPunchRecordVO.getLeaveList().get(1);
                                } else {
                                    attendPunchRecordLeaveListLeave = new AttendPunchRecordLeaveListVO();
                                }
                                for (int i = 0; i < attendPunchRecordVO.getLeaveList().size(); i++) {
                                    String leaveTime = attendPunchRecordVO.getLeaveList().get(i).getLeaveTime();
                                    String leaveTimeReturn = attendPunchRecordLeaveListVO.getLeaveTime();
                                    if (StrKit.isEmpty(arriveTime) || StrKit.isEmpty(leaveTime)) {
                                        continue;
                                    }
                                    if (DateKit8.parseDateTime(leaveTime).getTime() <
                                            DateKit8.parseDateTime(arriveTime).getTime()) {
                                        if (DateKit8.parseDateTime(leaveTimeReturn).getTime() <=
                                                DateKit8.parseDateTime(leaveTime).getTime()) {
                                            attendPunchRecordLeaveListVO = attendPunchRecordVO.getLeaveList().get(i);
                                        }
                                    } else {
                                        attendPunchRecordLeaveListLeave = attendPunchRecordVO.getLeaveList().get(i);
                                    }
                                }
                                attendPunchRecordLeaveOne = attendPunchRecordLeaveListVO;
                                attendBean.setLeaveOne(attendPunchRecordLeaveListVO);
                                // 第二次下班卡为最后一条记录
                                attendPunchRecordLeaveTwo = attendPunchRecordLeaveListLeave;
                                attendBean.setLeaveTwo(attendPunchRecordLeaveListLeave);
                            } else {
                                // 如果只有一次上班卡记录  下班卡记录取最后一条
                                attendPunchRecordLeaveOne = attendPunchRecordVO.getLeaveList().get(attendPunchRecordVO.getLeaveList().size() - 1);
                                attendBean.setLeaveOne(attendPunchRecordLeaveOne);
                            }
                        } else if (!CollectionUtils.isEmpty(attendPunchRecordVO.getLeaveList())
                                && !CollectionUtils.isEmpty(attendPunchRecordVO.getArriveList())) {
                            attendPunchRecordLeaveOne = attendPunchRecordVO.getLeaveList().get(0);
                            attendBean.setLeaveOne(attendPunchRecordLeaveOne);
                        }
                        if (attendPunchRecordVO.getLeaveList().size() > 1
                                && attendPunchRecordVO.getArriveList().size() > 1) {
                            attendBean.setLeaveStatus(attendPunchRecordLeaveOne.getLeaveStatus());
                            attendBean.setLeaveTime(attendPunchRecordLeaveOne.getLeaveTime());
                            attendBean.setLeavePlace(attendPunchRecordLeaveOne.getLeavePlace());
                            attendBean.setLeaveStatusTwo(attendPunchRecordLeaveTwo.getLeaveStatus());
                            attendBean.setLeaveTimeTwo(attendPunchRecordLeaveTwo.getLeaveTime());
                            attendBean.setLeavePlaceTwo(attendPunchRecordLeaveTwo.getLeavePlace());
                        } else if (attendPunchRecordVO.getArriveList().size() == 1) {
                            attendBean.setLeaveStatus(attendPunchRecordLeaveOne.getLeaveStatus());
                            attendBean.setLeaveTime(attendPunchRecordLeaveOne.getLeaveTime());
                            attendBean.setLeavePlace(attendPunchRecordLeaveOne.getLeavePlace());
                        }
                        attendBean.setIsCalibrationArrive(attendPunchRecordVO.getIsCalibrationArrive());
                        attendBean.setIsCalibrationLeave(attendPunchRecordVO.getIsCalibrationLeave());
                    }
                    attendBean.setWorkDate(this.workTime(attendBean.getWorkTime()));
                    if (attendBean.getNormalDay() != null && attendBean.getUnusualDay() != null) {
                        attendBean.setCount(attendBean.getNormalDay() - attendBean.getUnusualDay());
                    }
                }).collect(Collectors.toList());
    }

    @Override
    public List<AttendPunchRecordVO> exportAttendByDay(AttendPunchRecordQuery attendPunchRecordQuery, TokenUser tokenUser) {
        // 去重empInfoIdList
        if (!CollectionUtils.isEmpty(attendPunchRecordQuery.getEmpInfoIdList())) {
            attendPunchRecordQuery.setEmpInfoIdList(attendPunchRecordQuery.getEmpInfoIdList()
                    .stream().distinct().collect(Collectors.toList()));
        }
        // 开启循环模式
        List<Date> dateList = new ArrayList<>();
        Date startDate = DateKit8.parseDate(attendPunchRecordQuery.getAttendStart());
        Date endDate = DateKit8.parseDate(attendPunchRecordQuery.getAttendEnd());
        while (startDate.getTime() <= endDate.getTime()) {
            dateList.add(startDate);
            startDate = DateKit8.addDays(startDate, 1);
        }
        List<AttendPunchRecordVO> attendPunchRecordAll = new ArrayList<>();
        List<AttendPunchRecordVO> attendPunchRecordError = new ArrayList<>();
        for (Date date : dateList) {
            List<String> dateStr = ArrayKit.split(DateKit8.format2Date(date), "-");
            if (dateStr.size() < 3) {
                throw new ParamException("时间转换异常，请联系管理员或稍后重试!");
            }
            attendPunchRecordQuery.setYear(dateStr.get(0));
            attendPunchRecordQuery.setMonth(dateStr.get(1));
            attendPunchRecordQuery.setDay(dateStr.get(2));
            // 根据时间判断  2021年8月21日之后的数据 工作时长求和
            Date limitDate = DateKit8.parseDate("2021-08-21 00:00:00");
            List<AttendPunchRecordVO> attendPunchRecordVOList;
            if (date.getTime() > limitDate.getTime()) {
                // 新数据 求和
                attendPunchRecordVOList = attendPunchRecordDAO
                        .selectAttendByDay(attendPunchRecordQuery, tokenUser.getSiteId());
            } else {
                // 取最后一条
                attendPunchRecordVOList = attendPunchRecordDAO
                        .selectAttendByDayTwo(attendPunchRecordQuery, tokenUser.getSiteId());
            }
            if (!CollectionUtils.isEmpty(attendPunchRecordVOList)) {
                attendPunchRecordAll.addAll(attendPunchRecordVOList);
            }
        }

        return attendPunchRecordAll.stream().peek(attendBean -> {
            AttendPunchRecordVO attendPunchRecordVO =
                    this.arriveAndLeave2(attendBean.getOrderByArrive(),
                            attendBean.getOrderByLeave(), attendBean.getCalibration());
            if (attendPunchRecordVO != null) {
                // 如果上班集合都有时间  则按照时间排序
                if (attendPunchRecordVO.getArriveList() != null) {
                    List<AttendPunchRecordArriveListVO> attendPunchRecordArriveListVOS
                            = attendPunchRecordVO.getArriveList();
                    AtomicBoolean sort = new AtomicBoolean(true);
                    attendPunchRecordArriveListVOS.forEach(attendPunchRecordArriveListVO -> {
                        if (StrKit.isEmpty(attendPunchRecordArriveListVO.getArriveTime())) {
                            sort.set(false);
                        }
                    });
                    if (sort.get()) {
                        Collections.sort(attendPunchRecordArriveListVOS);
                    }
                }
                // 如果下班集合都有时间  则按照时间排序
                if (attendPunchRecordVO.getLeaveList() != null) {
                    List<AttendPunchRecordLeaveListVO> attendPunchRecordLeaveListVOList
                            = attendPunchRecordVO.getLeaveList();
                    AtomicBoolean sort = new AtomicBoolean(true);
                    attendPunchRecordLeaveListVOList.forEach(attendPunchRecordLeaveListVO -> {
                        if (StrKit.isEmpty(attendPunchRecordLeaveListVO.getLeaveTime())) {
                            sort.set(false);
                        }
                    });
                    if (sort.get()) {
                        Collections.sort(attendPunchRecordLeaveListVOList);
                    } else {
                        Collections.reverse(attendPunchRecordVO.getLeaveList());
                    }
                }
                attendBean.setArriveList(attendPunchRecordVO.getArriveList());
                attendBean.setLeaveList(attendPunchRecordVO.getLeaveList());
                if (attendPunchRecordVO.getArriveList().size() > 1) {
                    AttendPunchRecordArriveListVO attendPunchRecordArriveOne = attendPunchRecordVO.getArriveList().get(0);
                    AttendPunchRecordArriveListVO attendPunchRecordArriveTwo = attendPunchRecordVO.getArriveList().get(1);
                    attendBean.setArriveStatus(attendPunchRecordArriveOne.getArriveStatus());
                    attendBean.setArriveTime(attendPunchRecordArriveOne.getArriveTime());
                    attendBean.setArrivePlace(attendPunchRecordArriveOne.getArrivePlace());
                    attendBean.setArriveStatusTwo(attendPunchRecordArriveTwo.getArriveStatus());
                    attendBean.setArriveTimeTwo(attendPunchRecordArriveTwo.getArriveTime());
                    attendBean.setArrivePlaceTwo(attendPunchRecordArriveTwo.getArrivePlace());
                } else if (attendPunchRecordVO.getArriveList().size() == 1) {
                    AttendPunchRecordArriveListVO attendPunchRecordArriveOne = attendPunchRecordVO.getArriveList().get(0);
                    attendBean.setArriveStatus(attendPunchRecordArriveOne.getArriveStatus());
                    attendBean.setArriveTime(attendPunchRecordArriveOne.getArriveTime());
                    attendBean.setArrivePlace(attendPunchRecordArriveOne.getArrivePlace());
                }
                AttendPunchRecordLeaveListVO attendPunchRecordLeaveOne = new AttendPunchRecordLeaveListVO();
                AttendPunchRecordLeaveListVO attendPunchRecordLeaveTwo = new AttendPunchRecordLeaveListVO();
                if (attendPunchRecordVO.getLeaveList().size() > 1) {
                    if (attendPunchRecordVO.getArriveList().size() > 1) {
                        // 如果有两条上班卡记录
                        String arriveTime = attendPunchRecordVO.getArriveList().get(1).getArriveTime();
                        // 找到第一次上班到第二次上班的时间段中最后的一次下班打卡记录
                        AttendPunchRecordLeaveListVO attendPunchRecordLeaveListVO = attendPunchRecordVO.getLeaveList().get(0);
                        AttendPunchRecordLeaveListVO attendPunchRecordLeaveListLeave;
                        if ("下班缺卡".equals(attendPunchRecordVO.getLeaveList().get(1).getLeaveStatus())) {
                            attendPunchRecordLeaveListLeave = attendPunchRecordVO.getLeaveList().get(1);
                        } else {
                            attendPunchRecordLeaveListLeave = new AttendPunchRecordLeaveListVO();
                        }
                        for (int i = 0; i < attendPunchRecordVO.getLeaveList().size(); i++) {
                            String leaveTime = attendPunchRecordVO.getLeaveList().get(i).getLeaveTime();
                            String leaveTimeReturn = attendPunchRecordLeaveListVO.getLeaveTime();
                            if (StrKit.isEmpty(arriveTime) || StrKit.isEmpty(leaveTime)) {
                                continue;
                            }
                            if (DateKit8.parseDateTime(leaveTime).getTime() <
                                    DateKit8.parseDateTime(arriveTime).getTime()) {
                                if (DateKit8.parseDateTime(leaveTimeReturn).getTime() <=
                                        DateKit8.parseDateTime(leaveTime).getTime()) {
                                    attendPunchRecordLeaveListVO = attendPunchRecordVO.getLeaveList().get(i);
                                }
                            } else {
                                attendPunchRecordLeaveListLeave = attendPunchRecordVO.getLeaveList().get(i);
                            }
                        }
                        attendPunchRecordLeaveOne = attendPunchRecordLeaveListVO;
                        attendBean.setLeaveOne(attendPunchRecordLeaveListVO);
                        // 第二次下班卡为最后一条记录
                        attendPunchRecordLeaveTwo = attendPunchRecordLeaveListLeave;
                        attendBean.setLeaveTwo(attendPunchRecordLeaveListLeave);
                    } else {
                        // 如果只有一次上班卡记录  下班卡记录取最后一条
                        attendPunchRecordLeaveOne = attendPunchRecordVO.getLeaveList().get(attendPunchRecordVO.getLeaveList().size() - 1);
                        attendBean.setLeaveOne(attendPunchRecordVO.getLeaveList().get(attendPunchRecordVO.getLeaveList().size() - 1));
                    }
                } else if (!CollectionUtils.isEmpty(attendPunchRecordVO.getLeaveList())
                        && !CollectionUtils.isEmpty(attendPunchRecordVO.getArriveList())) {
                    attendPunchRecordLeaveOne = attendPunchRecordVO.getLeaveList().get(0);
                    attendBean.setLeaveOne(attendPunchRecordVO.getLeaveList().get(0));
                }

                if (attendPunchRecordVO.getLeaveList().size() > 1
                        && attendPunchRecordVO.getArriveList().size() > 1) {
                    attendBean.setLeaveStatus(attendPunchRecordLeaveOne.getLeaveStatus());
                    attendBean.setLeaveTime(attendPunchRecordLeaveOne.getLeaveTime());
                    attendBean.setLeavePlace(attendPunchRecordLeaveOne.getLeavePlace());
                    attendBean.setLeaveStatusTwo(attendPunchRecordLeaveTwo.getLeaveStatus());
                    attendBean.setLeaveTimeTwo(attendPunchRecordLeaveTwo.getLeaveTime());
                    attendBean.setLeavePlaceTwo(attendPunchRecordLeaveTwo.getLeavePlace());
                } else if (attendPunchRecordVO.getArriveList().size() == 1) {
                    attendBean.setLeaveStatus(attendPunchRecordLeaveOne.getLeaveStatus());
                    attendBean.setLeaveTime(attendPunchRecordLeaveOne.getLeaveTime());
                    attendBean.setLeavePlace(attendPunchRecordLeaveOne.getLeavePlace());
                }
                attendBean.setIsCalibrationArrive(attendPunchRecordVO.getIsCalibrationArrive());
                attendBean.setIsCalibrationLeave(attendPunchRecordVO.getIsCalibrationLeave());
            }
            attendBean.setWorkDate(this.workTime(attendBean.getWorkTime()));
        }).collect(Collectors.toList());
    }

    @Override
    public List<AttendPunchRecordVO> exportAttendByTime(AttendPunchRecordQuery attendPunchRecordQuery, TokenUser tokenUser) {
        // 去重empInfoIdList
        if (!CollectionUtils.isEmpty(attendPunchRecordQuery.getEmpInfoIdList())) {
            attendPunchRecordQuery.setEmpInfoIdList(attendPunchRecordQuery.getEmpInfoIdList()
                    .stream().distinct().collect(Collectors.toList()));
        }
        // 构造查询时间范围
        attendPunchRecordQuery.setStartTime(attendPunchRecordQuery.getAttendStart().replaceAll("-", ""));
        attendPunchRecordQuery.setEndTime(attendPunchRecordQuery.getAttendEnd().replaceAll("-", ""));
        List<AttendPunchRecordVO> returnAttendPunchRecord = new ArrayList<>();
        List<AttendPunchRecordVO> attendPunchRecordAll = attendPunchRecordDAO
                .selectAttendByTime(attendPunchRecordQuery, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(attendPunchRecordAll)) {
            return new ArrayList<>();
        }
        // 处理考勤记录  构造前端需要展示的信息
        // 根据打卡年分组
        Map<String, List<AttendPunchRecordVO>> attendPunchRecordByYearMap = attendPunchRecordAll
                .stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getYear));
        for (String year : attendPunchRecordByYearMap.keySet()) {
            List<AttendPunchRecordVO> attendPunchRecordYearList = attendPunchRecordByYearMap.get(year);
            // 根据打卡月分组
            Map<String, List<AttendPunchRecordVO>> attendPunchRecordByMonthMap = attendPunchRecordYearList
                    .stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getMonth));
            for (String month : attendPunchRecordByMonthMap.keySet()) {
                List<AttendPunchRecordVO> attendPunchRecordMonthList = attendPunchRecordByMonthMap.get(month);
                // 根据打卡日分组
                Map<String, List<AttendPunchRecordVO>> attendPunchRecordByDayMap = attendPunchRecordMonthList
                        .stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getDay));
                for (String day : attendPunchRecordByDayMap.keySet()) {
                    List<AttendPunchRecordVO> attendPunchRecordDayList = attendPunchRecordByDayMap.get(day);
                    // 根据empInfoId分组
                    Map<String, List<AttendPunchRecordVO>> attendPunchRecordByEmpInfoIdMap = attendPunchRecordDayList
                            .stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getEmpInfoId));
                    for (String empInfoId : attendPunchRecordByEmpInfoIdMap.keySet()) {
                        List<AttendPunchRecordVO> attendPunchRecordEmpInfoIdList = attendPunchRecordByEmpInfoIdMap.get(empInfoId);
                        returnAttendPunchRecord.add(buildReturnAttendPunchRecordVO(attendPunchRecordEmpInfoIdList));
                    }
                }
            }
        }
        if (returnAttendPunchRecord.size() > 2000) {
            throw new ParamException("导出数量不能超过2000，请分批进行");
        }
        returnAttendPunchRecord = returnAttendPunchRecord.stream().sorted(
                Comparator.comparing(AttendPunchRecordVO::getTimeDay)).collect(Collectors.toList());
        return returnAttendPunchRecord.stream().peek(attendBean -> {
            if (attendBean.getArriveOne() != null) {
                attendBean.setArriveStatus(attendBean.getArriveOne().getArriveStatus());
                attendBean.setArriveTime(attendBean.getArriveOne().getArriveTime());
                attendBean.setArrivePlace(attendBean.getArriveOne().getArrivePlace());
            }
            if (attendBean.getArriveTwo() != null) {
                attendBean.setArriveStatusTwo(attendBean.getArriveTwo().getArriveStatus());
                attendBean.setArriveTimeTwo(attendBean.getArriveTwo().getArriveTime());
                attendBean.setArrivePlaceTwo(attendBean.getArriveTwo().getArrivePlace());
            }
            if (attendBean.getLeaveOne() != null) {
                attendBean.setLeaveStatus(attendBean.getLeaveOne().getLeaveStatus());
                attendBean.setLeaveTime(attendBean.getLeaveOne().getLeaveTime());
                attendBean.setLeavePlace(attendBean.getLeaveOne().getLeavePlace());
            }
            if (attendBean.getLeaveTwo() != null) {
                attendBean.setLeaveStatusTwo(attendBean.getLeaveTwo().getLeaveStatus());
                attendBean.setLeaveTimeTwo(attendBean.getLeaveTwo().getLeaveTime());
                attendBean.setLeavePlaceTwo(attendBean.getLeaveTwo().getLeavePlace());
            }
        }).collect(Collectors.toList());
    }

    @Override
    public Map<String, Integer> getPunchEmpMonthCountDTOList(List<String> planIdList, String yearAndMonth, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(planIdList)) {
            return null;
        } else {
            Map<String, Integer> hashMap = new HashMap<>();
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

            // 当前月份一共有多少天
            Integer year = Integer.valueOf(yearAndMonth.split("-")[0]).intValue();
            Integer month = Integer.valueOf(yearAndMonth.split("-")[1]).intValue();
            Integer days = HrKit.getDays(year, month);
            String monthStr = month < 10 ? "0" + month : "" + month;

            // 按年月查询法定节假日列表

            org.jsola.admin.query.GregorianCalendarQuery gregorianCalendarQuery = new org.jsola.admin.query.GregorianCalendarQuery();
            gregorianCalendarQuery.setYear(year);
            gregorianCalendarQuery.setMonth(month);
            List<org.jsola.admin.entity.GregorianCalendarDO> gregorianCalendarList = gregorianCalendarProviderService.selectClendar(gregorianCalendarQuery, tokenUser.getSiteId());

            for (String planId : planIdList) {
                Integer workDays = 0;
                AttendPlanDO attendPlanDO = attendPlanService.selectByIdIgnoreValid(planId);
                // 根据考勤规则ID查询考勤打卡时间(hr_attend_punch_time)
                AttendPunchTimeQuery attendPunchTimeQuery = new AttendPunchTimeQuery();
                attendPunchTimeQuery.setAttendPlanId(planId);
                List<AttendPunchTimeDO> attendPunchTimeList = attendPunchTimeService.selectDO(attendPunchTimeQuery, tokenUser.getSiteId());
                // 考勤日期列表
                List<String> weekDateList = new ArrayList<>();
                if (!CollectionUtils.isEmpty(attendPunchTimeList)) {
                    AttendPunchTimeDO attendPunchTime = attendPunchTimeList.get(0);

                    // 工作周
                    List<String> workWeekList = JSON.parseArray(attendPunchTime.getWorkWeekJson(), String.class);
                    if (CollectionUtils.isEmpty(workWeekList)) {

                    }

                    for (int i = 1; i <= days; i++) {
                        String dayStr = "";
                        if (i < 10) {
                            dayStr = "0" + i;
                        } else {
                            dayStr = i + "";
                        }
                        // 查询今天是星期几
                        String todayWeek = null;
                        try {
                            todayWeek = HrKit.getWeek(df.parse(year + "-" + month + "-" + dayStr));
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }

                        for (String workWeek : workWeekList) {
                            if (workWeek.equals(todayWeek)) {
                                // 工作日
                                workDays = workDays + 1;
                                weekDateList.add(year + "-" + monthStr + "-" + dayStr);
                            }
                        }
                    }

                }
                // 考勤规则下是否有不需要打卡的特殊日期
                AttendCalendarQuery attendCalendarQuery = new AttendCalendarQuery();
                attendCalendarQuery.setAttendPlanId(planId);
                // 是否考勤 1-是,0-否
//                attendCalendarQuery.setNeedAttend(true);
                List<AttendCalendarDO> calendarList = attendCalendarService.selectDO(attendCalendarQuery, tokenUser.getSiteId());
                if (!CollectionUtils.isEmpty(calendarList)) {
                    // 特殊日期处理
                    List<AttendCalendarDO> calendarListNeed = calendarList.stream().filter(item -> item.getNeedAttend()).collect(Collectors.toList());
                    List<String> needDateList = new ArrayList<>();
                    if (!CollectionUtils.isEmpty(calendarListNeed)) {
                        needDateList = calendarListNeed.stream().map(item -> {
                            return item.getYear() + "-" + item.getMonth() + "-" + item.getDay();
                        }).collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(needDateList)) {
                            // 差集
                            needDateList = needDateList.stream()
                                    .filter(item ->
                                            !weekDateList.contains(item))
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(needDateList)) {
                                // 加上特殊日期必须打卡天数
                                workDays = workDays + needDateList.size();
                            }
                        }

                    }
                    List<AttendCalendarDO> calendarListNoNeed = calendarList.stream().filter(item -> !item.getNeedAttend()).collect(Collectors.toList());
                    List<String> noNeedDateList = new ArrayList<>();
                    if (!CollectionUtils.isEmpty(calendarListNoNeed)) {
                        noNeedDateList = calendarListNoNeed.stream().map(item -> {
                            return item.getYear() + "-" + item.getMonth() + "-" + item.getDay();
                        }).collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(noNeedDateList)) {
                            // 交集
                            noNeedDateList = noNeedDateList.stream()
                                    .filter(weekDateList::contains)
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(noNeedDateList)) {
                                // 减去特殊日期不需打卡天数
                                workDays = workDays - noNeedDateList.size();
                            }
                        }
                    }
                }
                // 是否同步国家法定节假日
                if (attendPlanDO.getIsSynchLegalHoliday() == null ? false : attendPlanDO.getIsSynchLegalHoliday()) {
                    // 法定节假日处理（在考勤日期范围内且不在特殊日期范围内）
                    if (!CollectionUtils.isEmpty(gregorianCalendarList)) {
                        // 差集
                        List<org.jsola.admin.entity.GregorianCalendarDO> gregorianCalendarHolidayList = gregorianCalendarList.stream()
                                .filter(item -> !DateType.WORK_DAY.getValue().equals(item.getDateType()) && item.getIsCalendar())
                                .filter(item ->
                                        !calendarList.contains(DateKit8.format(item.getDate(), DateKit8.DATE)))
                                .collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(gregorianCalendarHolidayList)) {
                            //交集
                            gregorianCalendarHolidayList = gregorianCalendarHolidayList.stream()
                                    .filter(item -> !DateType.WORK_DAY.getValue().equals(item.getDateType()) && item.getIsCalendar())
                                    .filter(item ->
                                            weekDateList.contains(DateKit8.format(item.getDate(), DateKit8.DATE)))
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(gregorianCalendarHolidayList)) {
                                // 减去法定节假日不需打卡天数
                                workDays = workDays - gregorianCalendarHolidayList.size();
                            }
                        }

                        // 法定节假日补班（不在考勤日期范围内且不在特殊日期范围内）
                        // 差集
                        List<org.jsola.admin.entity.GregorianCalendarDO> gregorianCalendarWorkDayList = gregorianCalendarList.stream()
                                .filter(item -> DateType.WORK_DAY.getValue().equals(item.getDateType()) && item.getIsCalendar())
                                .filter(item ->
                                        !calendarList.contains(DateKit8.format(item.getDate(), DateKit8.DATE)))
                                .collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(gregorianCalendarWorkDayList)) {
                            // 差集
                            gregorianCalendarWorkDayList = gregorianCalendarWorkDayList.stream()
                                    .filter(item -> DateType.WORK_DAY.getValue().equals(item.getDateType()) && item.getIsCalendar())
                                    .filter(item ->
                                            !weekDateList.contains(DateKit8.format(item.getDate(), DateKit8.DATE)))
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(gregorianCalendarWorkDayList)) {
                                // 加上法定节假日补班需要打卡天数
                                workDays = workDays + gregorianCalendarWorkDayList.size();
                            }
                        }
                    }
                }

                hashMap.put(planId, workDays);
            }
            return hashMap;
        }
    }

    @Override
    public void showExportTime(List<AttendPunchRecordVO> attendPunchRecordVOList) {
        if (CollectionUtils.isEmpty(attendPunchRecordVOList)) {
            return;
        }
        for (AttendPunchRecordVO attendPunchRecordVO : attendPunchRecordVOList) {
            // 时间只取时分秒
            if (StrKit.isNotEmpty(attendPunchRecordVO.getArriveTime())) {
                String arriveTime = attendPunchRecordVO.getArriveTime().split(" ")[1];
                attendPunchRecordVO.setArriveTime(arriveTime);
            }
            if (StrKit.isNotEmpty(attendPunchRecordVO.getLeaveTime())) {
                String arriveTime = attendPunchRecordVO.getLeaveTime().split(" ")[1];
                attendPunchRecordVO.setLeaveTime(arriveTime);
            }
            if (StrKit.isNotEmpty(attendPunchRecordVO.getArriveTimeTwo())) {
                String arriveTime = attendPunchRecordVO.getArriveTimeTwo().split(" ")[1];
                attendPunchRecordVO.setArriveTimeTwo(arriveTime);
            }
            if (StrKit.isNotEmpty(attendPunchRecordVO.getLeaveTimeTwo())) {
                String arriveTime = attendPunchRecordVO.getLeaveTimeTwo().split(" ")[1];
                attendPunchRecordVO.setLeaveTimeTwo(arriveTime);
            }
        }
    }

    @Override
    public List<AttendPunchRecordVO> filtration(List<AttendPunchRecordVO> attendPunchRecordAll) {
        List<AttendPunchRecordVO> attendPunchRecordError = new ArrayList<>();
        // 按照人员id进行分组
        Map<String, List<AttendPunchRecordVO>> attendPunchRecordGroupingByEmpInfoId =
                attendPunchRecordAll.stream().collect(Collectors.groupingBy(AttendPunchRecordVO::getEmpInfoId));
        for (String empInfoId : attendPunchRecordGroupingByEmpInfoId.keySet()) {
            List<AttendPunchRecordVO> attendPunchRecordVOList =
                    attendPunchRecordGroupingByEmpInfoId.get(empInfoId);
            // 过滤正常的数据
            attendPunchRecordVOList.removeIf(attendPunchRecordVO -> {
                boolean isF = true;
                if (StrKit.isNotEmpty(attendPunchRecordVO.getArriveStatus())
                        && !PunchStatus.NORMAL.getDesc().equals(attendPunchRecordVO.getArriveStatus())) {
                    isF = false;
                }
                if (StrKit.isNotEmpty(attendPunchRecordVO.getLeaveStatus())
                        && !PunchStatus.NORMAL.getDesc().equals(attendPunchRecordVO.getLeaveStatus())) {
                    isF = false;
                }
                if (StrKit.isNotEmpty(attendPunchRecordVO.getArriveStatusTwo())
                        && !PunchStatus.NORMAL.getDesc().equals(attendPunchRecordVO.getArriveStatusTwo())) {
                    isF = false;
                }
                if (StrKit.isNotEmpty(attendPunchRecordVO.getLeaveStatusTwo())
                        && !PunchStatus.NORMAL.getDesc().equals(attendPunchRecordVO.getLeaveStatusTwo())) {
                    isF = false;
                }
                return isF;
            });
            if (!CollectionUtils.isEmpty(attendPunchRecordVOList)) {
                attendPunchRecordVOList.get(0).setErrorNumber(attendPunchRecordVOList.size());
            }
            attendPunchRecordError.addAll(attendPunchRecordVOList);
        }
        return attendPunchRecordError;
    }
}




